2016-04-26 1 views
-1

J'ai créé un code de programmation de socket.Programmation de socket C++: Accepter et Recv ne bloquent pas le processus

et je mis en œuvre le programme côté serveur comme suit:

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

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

    while (1){ 
     EP_Test4 et; 
    } 

    return 0; 
} 

c'est un code principal. et comme vous pouvez le voir, une ligne de code est dans while-statement. , une classe est appelée, le constructeur de la classe est également appelé, puis la méthode "initEntryPoint()" est appelée.

EP_Test4::EP_Test4(){ 

    initEntryPoint(); 
} 

dans le code initEntryPoint, il existe une initiation de la méthode de la prise (InitCtrlSocket), un procédé de prise méthode de données de réception et de fermeture.

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

Et ces méthodes sont mises en œuvre comme comme suit

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(); 
} 

Mais lorsque le programme est exécuté, la méthode accept et la méthode recv ne sont pas en attente. les messages imprimés sont répétés comme ci-dessous l'image.

fonctionne parfois bien (en attente de la méthode de blocage), parfois non. Je ne comprends pas pourquoi cela arrive. Comme je sais, accepter la méthode et la méthode recv sont la méthode de "blocage". Mais pourquoi ces méthodes bloquent parfois, parfois non?

when the program is executed

+0

Il n'y a pas de preuve ici que the'accept() 'et' recv() 'méthodes ne sont pas le blocage, vous aren » t vérification d'erreur de la valeur de retour de 'recv()'. Votre code est très étrangement structuré pour un serveur TCP. Vous devez consulter un didacticiel et utiliser des threads pour les sockets acceptées. Ne perdez pas votre temps et notre bande passante en postant des images de texte ici. Postez le texte. – EJP

Répondre

1

Vous ne l'avez pas montré assez de code pour diagnostiquer votre problème. Et vous ne faites aucune erreur traitant sur accept() ou recv(). accept() échoue probablement et vous passez ensuite un socket non valide à recv().

Je vais sortir un membre et deviner que votre variable clen n'est pas initialisée. Si tel est le cas, il aura une valeur aléatoire, ce qui entraînera l'échec de accept() si clen est inférieur à sizeof(client_addr) et réussira si clen est supérieur ou égal à sizeof(client_addr).

Le paramètre addrlen de accept() est un paramètre IN/OUT:

addrlen [in, out]
Un pointeur facultatif à un nombre entier qui contient la longueur de la structure pointée par le paramètre adr .

...

L'entier désigné par addrlen contient initialement la quantité d'espace pointé par addr. Au retour, il contiendra la longueur réelle en octets de l'adresse retournée.

...

Le paramètre addr est un paramètre de résultat qui est rempli avec l'adresse de l'entité de liaison, comme cela est connu dans la couche de communication. Le format exact du paramètre addr est déterminé par la famille d'adresses dans laquelle la communication a lieu.Le addrlen est un paramètre de valeur-résultat; il devrait initialement contenir la quantité d'espace pointée par addr; au retour, il contiendra la longueur réelle (en octets) de l'adresse renvoyée.

Si vous ne donnez pas la taille d'entrée correctement, accept() échouera:

WSAEFAULT
Le paramètre addrlen est trop petit ou addr ne fait pas partie valide de l'espace d'adressage utilisateur .

Essayez ceci:

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; 
}