簡體   English   中英

C++ Socket 編程:Accept 和 Recv 方法不會阻塞進程

[英]C++ Socket Programming : Accept and Recv method do not block the process

我一直在創建套接字編程代碼。

我實現了服務器端程序如下:

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

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

    while (1){
        EP_Test4 et;
    }

    return 0;
}

這是一個主要代碼。 正如您所看到的,代碼行在 while 語句中。 在那里,一個類被調用,類中的構造函數也被調用,然后“initEntryPoint()”方法被調用。

EP_Test4::EP_Test4(){

    initEntryPoint();
}

在initEntryPoint代碼中,有發起socket方法(InitCtrlSocket)、接收數據方法和關閉socket方法。

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

但是當程序執行時,accept方法和recv方法都沒有等待。 因此打印的消息如下圖所示重復。

有時效果很好(等待阻塞方法),有時則不然。 我不明白為什么會這樣。 據我所知,accept 方法和 recv 方法是“阻塞”方法。 但是為什么這些方法有時會阻塞,有時不會?

程序執行時

您沒有顯示足夠的代碼來診斷您的問題。 並且您沒有對accept()recv()進行任何錯誤處理。 accept()可能失敗,然后您將無效的套接字傳遞給recv()

我要clen猜測您的clen變量未初始化。 如果是的話,它會產生一個隨機值,導致accept()來如果失敗clen恰好是小於sizeof(client_addr)並取得成功,如果clen恰好是大於或等於sizeof(client_addr)

accept()addrlen參數是一個IN/OUT參數:

addrlen [輸入,輸出]
一個指向整數的可選指針,該整數包含由 addr 參數指向的結構的長度。

...

addrlen 引用的整數最初包含 addr 指向的空間量。 返回時,它將包含返回地址的實際長度(以字節為單位)。

...

參數addr是一個結果參數,填充有連接實體的地址,如通信層所知。 addr 參數的確切格式由發生通信的地址族決定。 addrlen 是一個 value-result 參數; 它最初應該包含由 addr 指向的空間量; 返回時,它將包含返回地址的實際長度(以字節為單位)。

如果您沒有正確提供輸入大小, accept()將失敗:

WSAEFAULT
addrlen 參數太小或 addr 不是用戶地址空間的有效部分。

試試這個:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM