繁体   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