首先 recv() 无法读取从服务器发送的消息

First recv() cannot read message sent from server

我正在编写一个简单的 TCP 服务器和客户端,其中服务器将消息回显给客户端。但是我对来自客户端的第一个 read()/recv() 调用有疑问。每当客户端连接到服务器时,它都会发送一条欢迎消息,但我无法在客户端显示欢迎消息。我从 recv()/read() 中得到的 return 是 0,这表明套接字已关闭或读取了 0 个字节。我知道它没有关闭,因为服务器回显消息但有延迟(如下所示)。在我从客户端写入服务器后,read()/recv() 工作正常。所以我的问题是: 为什么第一个 read()/recv() 调用收到 return 0?

TLDR;我的客户端没有读取()/recv() 从服务器发送的欢迎信息。我做错了什么?

服务器与客户端交互(通知为空'Welcome message'):

如您所见,套接字未关闭,因此 read()/recv() returns 0 的唯一原因是因为读取了 0 个字节。

客户代码:

(SETUP NOT INCLUDED)
printf("Connected. \n");

memset(buffer, 0, 1025);

/********* PROBLEM IS THIS READ()/RECV() **********/
n = recv(sockfd, buffer, strlen(buffer), NULL);
if(n == 0){ //
     //error("Error reading\n");
     printf("Error reading socket.");
}

printf("Welcome message: \n%s", buffer);

while(1){
    printf("\nPlease enter message: \n");

    memset(buffer, 0, 256);
    fgets(buffer, 255, stdin);
    printf("You sent: %s", buffer);

    n = write(sockfd, buffer, strlen(buffer));
    if(n <= 0)
    {
        error("Error writing socket. \n");
    }
    //om bye, break
    memset(buffer, 0, 256);
    //Läser här endast efter write
    n = read(sockfd, buffer, 255);
    if(n < 0)
    {
        error("Error reading from socket. \n");
    }

    printf("You received: %s", buffer);
}
//end while
close(sockfd);
return 0;

相关服务器代码:

 while(TRUE)
{
    /* Clear socket set */
    FD_ZERO(&readfds);
    /* Add master socket to set */
    FD_SET(masterSocket, &readfds);
    /* For now maxSd is highest */
    maxSd = masterSocket;

    /* Add child sockets to set, will be 0 first iteration */
    for(int i = 0; i < maxClients ; i++)
    {
        sd = clientSockets[i]; // sd = socket descriptor
        /* If valid socket descriptor */
        if(sd > 0)
        {
            FD_SET(sd, &readfds);
        }
        /* Get highest fd number, needed for the select function (later) */
        if(sd > maxSd)
        {   
            maxSd = sd;
        }
    }//end for-loop

    /* Wait for activity on any socket */
    activity = select(maxSd +1, &readfds, NULL, NULL, NULL);

    if((activity < 0) && (errno != EINTR))
    {
        printf("****** Error on select. ******\n"); //no need for exit.
    }

    /* If the bit for the file descriptor fd is set in the 
    file descriptor set pointed to by fdset */
    /* If something happend in the master socket, its a new connection */
    if(FD_ISSET(masterSocket, &readfds))
    {
        //står här och läser
        if((newSocket = accept(masterSocket, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0)
        {
            perror("****** Could not accept new socket. ******\n");
            exit(EXIT_FAILURE);
        }

        /* Print info about connector */
        printf("New connection, socket fd is %d, ip is: %s, port: %d\n", newSocket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));

        /**************** THIS IS THE WRITE THAT DOESN'T GET DISPLAYED ON CLIENT ******************/
        if( send(newSocket, message, strlen(message), 0) != strlen(message))
        {
             perror("****** Could not sent welcome message to new socket. ******\n");
        }

        puts("Welcome message sen successfully");

        /* Add new socket to array of clients */
        for(int i = 0; i < maxClients; i++)
        {
            if(clientSockets[i] == 0)
            {
                clientSockets[i] = newSocket;
                printf("Adding socket to list of client at index %d\n", i);
                break;
            }
        }
    }//end masterSocket if
    /* Else something happend at client side */
    for(int i = 0; i < maxClients; i++)
    {
        sd = clientSockets[i];

        if(FD_ISSET(sd, &readfds))
        {   
            /* Read socket, if it was closing, else read value */
            //denna read kan vara fel
            if((valread = read( sd, buffer, 1024)) == 0)
            {
                getpeername( sd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
                printf("Host disconnected, ip %s, port %d.\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));

                close(sd);
                clientSockets[i] = 0;
            }
            else
            {
                buffer[valread] = '[=11=]';
                send(sd, buffer, strlen(buffer), 0);
            }
        }
    }

我知道这是一大堆文字,但我非常感谢所有花时间解决这个问题的人。

我不确定这是否是问题的唯一原因,但是...在您的客户端代码中...

memset(buffer, 0, 1025);

然后不久之后...

n = recv(sockfd, buffer, strlen(buffer), NULL);

strlen(buffer) 此时将 return 为零,因此对 recv 的调用完全按照要求执行 - 它读取零字节。

另请注意,服务器发送的欢迎消息不是空终止的。因此,您的客户端无法知道欢迎消息何时结束以及后续数据何时开始。

recv 的第三个参数指定要从套接字读取的字节数。现在看看你的代码:

memset(buffer, 0, 1025);
recv(sockfd, buffer, strlen(buffer), NULL);

首先,将整个缓冲区清零,然后对其调用 strlen。难怪 returns 0,因为 strlen 计算非零字节。

相反,将缓冲区长度放入一个变量中并在任何地方使用它:

const int bufSize = 1025;
memset(buffer, 0, bufSize);
recv(sockfd, buffer, bufSize, NULL);