2016-04-26 6 views
-1

Ich habe einen Socket-Programmiercode erstellt.C++ Socket-Programmierung: Accept und Recv-Methode blockieren nicht den Prozess

und ich implementiert serverseitige Programm wie folgt:

#include "Common.h" 
#include "EP_Test4.h" 

int main() 
{ 
    printf("Start EP3 \n"); 

    while (1){ 
     EP_Test4 et; 
    } 

    return 0; 
} 

dies ist ein Hauptcode. und wie Sie sehen können, ist eine Codezeile in while-Anweisung. da wird eine Klasse aufgerufen, der Konstruktor in der Klasse wird auch aufgerufen, dann wird die Methode "initEntryPoint()" aufgerufen.

EP_Test4::EP_Test4(){ 

    initEntryPoint(); 
} 

im initEntryPoint Code gibt es eine Einleitung der Buchse Methode (InitCtrlSocket), Verfahren ein Empfangsdaten Verfahren und Schließbuchse.

void EP_Test4::initEntryPoint() 
{ 
    printf("[Waiting Restart Signal] \n"); 
    CSocket cCtrlEpSock; 
    cCtrlEpSock.InitCtrlSocket(); 
    cCtrlEpSock.RecvRestartEPMsg(); 
    cCtrlEpSock.CloseCtrlSocket(); 
} 

Und die Methode sind wie wie folgt implementiert

void CSocket::InitCtrlSocket(){ 

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { 
     printf("error\r\n"); 
    } 

    if ((EpCtrlServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))<0)   
    { 

     perror("socket error : "); 
     exit(1); 
    } 

    memset(&server_addr, 0, sizeof(server_addr)); 

    server_addr.sin_family = AF_INET; 
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    server_addr.sin_port = htons(6870); 

    if (bind(EpCtrlServerSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) 
    { 
     perror("bind error: "); 
     exit(1); 
    } 

    if (listen(EpCtrlServerSocket, 5)<0) 
    { 
     perror("listen error : "); 
     exit(1); 
    } 

    EpCtrlClientSocket = accept(EpCtrlServerSocket, (struct sockaddr *)&client_addr, &clen); 
} 

void CSocket::RecvRestartEPMsg(){ 
    char arrRecvCompleteMsg[50]; 
    memset(&arrRecvCompleteMsg, 0, sizeof(arrRecvCompleteMsg)); 

    int data_len = recv(EpCtrlClientSocket, (char*)&arrRecvCompleteMsg, sizeof(arrRecvCompleteMsg), 0); 
    cout << "RECV CTRL MSG : " << arrRecvCompleteMsg << endl; 
} 

void CSocket::CloseCtrlSocket(){ 

    closesocket(EpCtrlServerSocket); 
    closesocket(EpCtrlClientSocket); 
    WSACleanup(); 
} 

Aber wenn das Programm ausgeführt wird, akzeptiert das Verfahren und die recv Verfahren warten nicht. so gedruckte Nachrichten werden wie unten abgebildet wiederholt.

funktioniert manchmal gut (Warten auf die Blockierungsmethode), manchmal nicht. Ich verstehe nicht, warum das passiert. Wie ich weiß, akzeptieren Methode und Recv-Methode sind die "Blockierung" -Methode. Aber warum blockieren diese Methoden manchmal, manchmal nicht?

when the program is executed

+0

Es gibt keine Beweise dafür, dass hier the'accept() 'und' recv() 'Methoden nicht blockieren, Sie aren‘ t Fehlerprüfung des Rückgabewertes von 'recv()'. Ihr Code ist sehr seltsam für einen TCP-Server strukturiert. Sie müssen ein Tutorial lesen und Threads für die akzeptierten Sockets verwenden. Verschwenden Sie nicht Ihre Zeit und unsere Bandbreite, indem Sie hier Bilder von Text veröffentlichen. Veröffentlichen Sie den Text. – EJP

Antwort

1

Sie haben nicht genug Code zu diagnostizieren Ihr Problem gezeigt. Und Sie tun keine Fehlerbehandlung auf accept() oder recv(). accept() ist wahrscheinlich fehlgeschlagen und Sie übergeben dann einen ungültigen Socket an recv().

Ich gehe auf ein Bein und erraten, dass Ihre clen Variable nicht initialisiert ist. Ist dies der Fall, wird ein zufälliger Wert ausgegeben, der dazu führt, dass accept() fehlschlägt, wenn clen zufällig kleiner als sizeof(client_addr) ist, und erfolgreich ausgeführt wird, wenn clen zufällig größer oder gleich sizeof(client_addr) ist.

Der addrlen Parameter accept() ist ein IN/OUT Parameter:

addrlen [in, out]
Ein optionaler Zeiger auf eine ganze Zahl, die die Länge der Struktur enthält, auf die durch den Parameter addr .

...

Die Ganzzahl zunächst durch addrlen bezeichnet enthält die Menge an Speicherplatz, die von addr spitz. Bei der Rückkehr wird die tatsächliche Länge der zurückgegebenen Adresse in Bytes angegeben.

...

Der Parameter addr ist ein Ergebnis Parameter, der mit der Adresse der Anschlusseinheit eingefüllt, in Bezug auf die Schicht Kommunikation bekannt. Das genaue Format des Adr-Parameters wird durch die Adressfamilie bestimmt, in der die Kommunikation stattfindet.Die Adresse ist ein Wert-Ergebnis-Parameter; es sollte anfangs die Menge an Speicherplatz enthalten, auf die addr zeigt; Bei Rückgabe wird die tatsächliche Länge (in Byte) der zurückgegebenen Adresse angezeigt.

Wenn Sie die Eingangsgröße nicht korrekt angeben, wird accept() fehlschlagen:

WSAEFAULT
Der addrlen Parameter ist zu klein oder Adr ist kein gültiger Teil des Benutzeradressraum .

Versuchen Sie stattdessen:

clen = sizeof(client_addr); // <-- add this 
EpCtrlClientSocket = accept(EpCtrlServerSocket, (struct sockaddr *)&client_addr, &clen); 
if (EpCtrlClientSocket < 0) // <-- add this 
{ 
    perror("accept error : "); 
    exit(1); 
} 

void CSocket::RecvRestartEPMsg(){ 
    char arrRecvCompleteMsg[50];  
    int data_len = recv(EpCtrlClientSocket, arrRecvCompleteMsg, sizeof(arrRecvCompleteMsg), 0); 
    if (data_len > 0) // <-- add this 
    { 
     cout << "RECV CTRL MSG : "; 
     cout.write(arrRecvCompleteMsg, data_len); 
     cout << endl; 
    } 
    else 
     cout << "RECV CTRL ERR : " << endl; 
}