2016-04-26 8 views
-1

Я создаю код программирования сокета.Программирование сокетов C++: метод Accept и Recv не блокирует процесс

и я реализовал на стороне сервера программы следующим образом:

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

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

    while (1){ 
     EP_Test4 et; 
    } 

    return 0; 
} 

это является основной код. и, как вы видите, строка кода находится в while-statement. , вызывается класс, также вызывается конструктор в классе, затем вызывается метод initEntryPoint().

EP_Test4::EP_Test4(){ 

    initEntryPoint(); 
} 

в коде initEntryPoint, есть инициация методы сокета (InitCtrlSocket), способ приема данных и закрытие сокета метода.

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

И те, метод реализуются как следующим

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

Но когда программа выполняется, принимают метод и метод RECV не ждут. поэтому печатные сообщения повторяются, как показано ниже.

иногда работает хорошо (ожидание при блокировании), иногда нет. Я не понимаю, почему это происходит. Как я знаю, метод accept и recv - это метод блокировки. Но почему эти методы иногда блокируют, иногда нет?

when the program is executed

+0

Там нет никаких доказательств того, что здесь the'accept() 'и' RECV() 'методы не блокируют, вы Арен» t проверка ошибок возвращаемого значения 'recv()'. Ваш код очень странно структурирован для TCP-сервера. Вам необходимо проконсультироваться с учебником и использовать потоки для принятых сокетов. Не тратьте свое время и свою пропускную способность, публикуя здесь текст с текстом. Отправьте текст. – EJP

ответ

1

Вы не показали достаточно кода, чтобы диагностировать проблему. И вы не делаете любой обработки ошибок на accept() или recv(). accept(), скорее всего, не работает, и вы затем передаете недопустимый сокет на recv().

Я собираюсь выйти на конечность и угадать, что ваша переменная clen неинициализирована. Если это так, оно будет иметь случайное значение, что приведет к ошибке accept(), если clen окажется меньше sizeof(client_addr) и будет успешным, если clen окажется больше или равно sizeof(client_addr).

Параметр accept()addrlen является IN/OUT Параметр:

addrlen [In, Out]
Необязательный указатель на целое число, которое содержит длину структуры, указанной в параметре ADDR ,

...

Целое ссылается addrlen изначально содержит объем пространства, на которое указывает адрес. При возврате он будет содержать фактическую длину в байтах возвращаемого адреса.

...

Параметр адр является параметром результат, который заполняется с адресом соединительной сущности, как это известно в уровне связи. Точный формат параметра addr определяется семейством адресов, в котором происходит связь.Addrlen - параметр значения-результата; сначала он должен содержать объем пространства, на который указывает адр; по возврату он будет содержать фактическую длину (в байтах) возвращенного адреса.

Если вы не предоставите размер входного правильно, accept() не получится:

WSAEFAULT
addrlen параметр слишком мал или адр не является действительной частью адресного пространства пользователя ,

Попробуйте вместо этого:

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; 
} 
Смежные вопросы