2

현재 일부 코드에서는 매우 이상한 문제가 있습니다. 바로 다음에 선언 한 후에 정상적으로 보이는 변수는 액세스 위반이 발생합니다 (기본적으로 포인터는 여전히 같은 위치를 가리키고 있지만 메모리는 할당되지 않은 것 같습니다). 나는이 문제가 멀티 스레딩과 관련이 있다고 확신하지만, 멀티 스레딩을 처음 접한 이래로 그게 뭔지 전혀 모른다.포인터가 멀티 쓰레드 기능 선언 후 곧바로 할당 해제됩니다.

#include "Firewall.h" 
#include <Ws2tcpip.h> 

Firewall::Firewall(void) 
{ 
} 


Firewall::~Firewall(void) 
{ 
} 

void Firewall::parseFile(string filePath) 
{ 
    XMLNode xMainNode=XMLNode::openFileHelper(filePath.c_str(),"firewall"); 

    // Filtrage 
    XMLNode nodeFiltrage = xMainNode.getChildNode("filtrage"); 
    XMLNode currentNode; 

    for(int i=0; i < nodeFiltrage.nChildNode();i++) 
    { 
     currentNode = nodeFiltrage.getChildNode(i); 

     string nom = currentNode.getName(); 

     if(nom == "permettre") 
      mapFiltrage_.insert(pair<int,bool>(atoi(currentNode.getAttribute().lpszValue), true)); 

     else if(nom == "bloquer") 
      mapFiltrage_.insert(pair<int,bool>(atoi(currentNode.getAttribute().lpszValue), false)); 
    } 

    // Redirection 

    XMLNode nodeRedirection = xMainNode.getChildNode("redirection"); 
    XMLNode currentSubNode; 

    for(int i = 0; i < nodeRedirection.nChildNode(); i++) 
    { 
     currentNode = nodeRedirection.getChildNode(i); 
     currentSubNode = currentNode.getChildNode("source"); 

     SourceDestination source((string)currentSubNode.getAttribute("adresse"), atoi(currentSubNode.getAttribute("port"))); 

     currentSubNode = currentNode.getChildNode("destination"); 
     SourceDestination destination((string)currentSubNode.getAttribute("adresse"), atoi(currentSubNode.getAttribute("port"))); 

     mapRedirection_.insert(pair<SourceDestination, SourceDestination>(source,destination)); 

     pair<SourceDestination, SourceDestination> test; 
    } 


} 

void Firewall::initialiser() 
{ 
    std::map<int, bool>::iterator iterFiltrage = mapFiltrage_.begin(); 
    HANDLE handleThread; 

    std::string tempFiltrage = "localhost"; 
    thread_arg arg; 

    // Parcours et lancement des connexions de filtrage 
    while(iterFiltrage != mapFiltrage_.end()) 
    { 
     arg.port = (*iterFiltrage).first; 
     arg.host = tempFiltrage; 
     arg.objRef = this; 

     handleThread = CreateThread(NULL, 0, listenThread, &arg, 0, NULL); 
     listeThread_.push_back(handleThread); 

     iterFiltrage++; 
    } 

    // Parcours et lancement des connexions de redirection 
    std::map<SourceDestination, SourceDestination>::iterator iterRedirection = mapRedirection_.begin(); 

    while(iterRedirection != mapRedirection_.end()) 
    { 
     // Éviter la duplication inutile des sockets 
     if(mapFiltrage_.find((*iterRedirection).first.Port()) == mapFiltrage_.end()) 
     { 
      arg.host = (*iterRedirection).first.Host(); 
      arg.port = (*iterRedirection).first.Port(); 
      arg.objRef = this; 

      handleThread = CreateThread(NULL, 0, listenThread, &arg, 0, NULL); 
      listeThread_.push_back(handleThread); 
     } 

     iterRedirection++; 
    } 
} 


DWORD WINAPI Firewall::listenThread(LPVOID lpParam) 
{ 
    thread_arg* temp = (thread_arg*)lpParam; 
    Firewall* firewallRef = temp->objRef; 

    return firewallRef->runThread(lpParam); 
} 

DWORD Firewall::runThread(LPVOID lpParam) 
{ 
    thread_arg* infosSocket = (thread_arg*)lpParam; 

    // Créer le socket et l'attacher à la source 
    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); 

    if(sock == INVALID_SOCKET) 
    { 
     cout << "Erreur de creation de socket" << endl; 
     return EXIT_FAILURE; 
    } 

    //Recuperation de l'adresse locale 
    hostent *thisHost; 
    const char* test = infosSocket->host.c_str(); 
    thisHost=gethostbyname(test); 
    char* ip; 
    ip=inet_ntoa(*(struct in_addr*) *thisHost->h_addr_list); 

    SOCKADDR_IN sin; 
    sin.sin_addr.s_addr = inet_addr(ip); 
    sin.sin_family = AF_INET; 
    sin.sin_port = htons(infosSocket->port); 



    if(bind(sock, (SOCKADDR*)&sin, sizeof(sin)) == SOCKET_ERROR) 
    { 
     cout << "Erreur de binding" << endl; 
     return EXIT_FAILURE; 
    } 

    // Contexte du client 
    SOCKADDR_IN csin; 
    SOCKET csock; 
    socklen_t crecsize = sizeof(csin); 

    listeSocket_.push_back(sock); 
    listeSocket_.push_back(csock); 

    // Écouter sur le port 
    if(listen(sock, 5) == SOCKET_ERROR) 
    { 
     cout << "Erreur de listen" << endl; 
     return EXIT_FAILURE; 
    } 

    //csock = accept(sock, (SOCKADDR*)&csin, &crecsize); 

    return EXIT_SUCCESS; 
} 

void Firewall::quitter() 
{ 
    // Fermer les sockets 
    vector<SOCKET>::iterator iter1 = listeSocket_.begin(); 

    while(iter1 != listeSocket_.end()) 
    { 
     closesocket((*iter1)); 
     iter1++; 
    } 

    // Fermer les threads 

    vector<HANDLE>::iterator iter2 = listeThread_.begin(); 

    while(iter2 != listeThread_.end()) 
    { 
     TerminateThread((*iter2), EXIT_SUCCESS); 
     CloseHandle((*iter2)); 
    } 
} 

고마워 : 여기

는 코드입니다.

답변

1

귀하의 문제는이 코드에 있습니다

thread_arg arg; 

loop(...) 
{ 
    arg = ...; 
    handleThread = CreateThread(..., &arg, ...); 
} 

는 모든 스레드가 여기에서 시작 같은 thread_arg 인스턴스의 주소를받습니다. 그런 다음, 다음 스레드를 시작하기 위해 이전에 시작된 스레드에서 해당 인스턴스를 다시 수정합니다. 해결 방법으로 필요한 인수 (호스트, 포트, this)와 스레드에 대한 HANDLE을 보유하는 구조를 만듭니다. 이 구조체를 std :: list에 저장 한 다음 해당 요소의 주소를 CreateThread()에 전달합니다.

코드에 또 다른 문제가 있습니다. 반환 값을 확인해야합니다. 명백한 오류가 모두 발견 되었다면 어떤 코드에 대한 도움을 요청하는 것이 훨씬 낫습니다. 이를 위해서는 예외를 사용하는 것이 가장 쉽습니다. 아마도 beginthread되어야 CreateThread()는() 대신에,이 라인에 추가되면 : 제 2 단계에서

if(handleThread == NULL) 
    throw std::runtime_error("CreateThread() failed"); 

를 Win32 오류 코드를 보유 runtime_error의 전용 예외 클래스를 생성 (참조 : GetLastError ()) 예외 메시지에 텍스트 오류 설명을 포함합니다 (FormatString() 참조). 이것은 아무 것도없는 많은 코드처럼 들릴지 모르지만이 코드는 한 번만 작성하면 여러 위치에서 다시 사용할 수 있습니다.

마지막으로 quitter()에는 두 가지 문제가 있습니다. 첫 번째는 무한 루프입니다.

for(; listeThread_.empty(); listeTread_.pop_back()) 
{ 
    TerminateThread(listeThread_.back(), EXIT_SUCCESS); 
    CloseHandle(listeThread_.back()); 
} 

당신도 동안 루프로 이것을 쓸 수 있습니다,하지만 난 개인적으로가 루프 반복의 수는 기본적으로 고정 된 경우 선호 : 당신을 가정하면 그것들을 닫은 후 핸들을 필요로하지 않습니다, 대신이 시도 . 물론 TerminateThread() 및 CloseHandle()의 반환 값을 확인해야합니다. 두 번째 문제는 TerminateThread()가 나쁜 생각 인 이유입니다. 반쯤 완료된 스레드 중간에 스레드가 종료 될 수 있기 때문입니다. 웹에서 "terminatethread harmful"을 검색하십시오. 이 시점에서 WaitForSingleObject()를 사용하여 작업이 끝날 때까지 기다리는 것뿐입니다.

+0

팁을 주셔서 감사합니다. 또한 나머지 코드를보고 내가 작성한 다른 실수를 지적 해 주셔서 감사합니다. – Djeezus

관련 문제