首页 文章

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

提问于
浏览
0

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

TLDR;我的客户端不读取()/ recv()从服务器发送的欢迎消息 . 我究竟做错了什么?

服务器和客户端交互(注意空'Welcome message'):

如您所见,套接字未关闭,因此read()/ recv()返回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] = '\0';
                send(sd, buffer, strlen(buffer), 0);
            }
        }
    }

我知道这是一个很大的文本墙,但我非常感谢那些花时间解决这个问题的人 .

2 回答

  • 2

    第_ arg到 recv 指定从套接字读取的字节数 . 现在看看你的代码:

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

    首先,将整个缓冲区清零,然后在其上调用 strlen . 难怪它返回0,因为 strlen 计算非零字节 .

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

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

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

    memset(buffer, 0, 1025);
    

    然后不久......

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

    strlen(buffer) 此时将返回零,因此对 recv 的调用完全按照请求执行 - 它读取零字节 .

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

相关问题