写入时始终阻止一个套接字描述符。选择不工作?

时间:2016-02-21 01:41:27

标签: c sockets tcp

您好我有一个服务器程序和一个客户端程序。服务器程序工作正常,因为我可以telnet到服务器,我可以任何顺序(如聊天室)读写,没有任何问题。但是我现在正在开发我的客户端程序,当我使用' select'并检查套接字描述符是否设置为读或写,它总是写入然后被阻止。在消息中,直到客户端发送一些数据才能通过。

如何在我的客户端修复此问题,以便我可以按任何顺序进行读写?

 while (quit != 1)
 {
    FD_ZERO(&read_fds);
    FD_ZERO(&write_fds);

    FD_SET(client_fd, &read_fds);
    FD_SET(client_fd, &write_fds);

    if (select(client_fd+1, &read_fds, &write_fds, NULL, NULL) == -1) 
    {
        perror("Error on Select");
        exit(2);
    }

    if (FD_ISSET(client_fd, &read_fds))
    {
        char newBuffer[100] = {'\0'};
        int bytesRead = read(client_fd, &newBuffer, sizeof(newBuffer));
        printf("%s",newBuffer);
    }

    if(FD_ISSET(client_fd, &write_fds))
    {
        quit = transmit(handle, buffer, client_fd);
    }
}

这是传输功能的代码

int transmit(char* handle, char* buffer, int client_fd)
{

    int n;
    printf("%s", handle);
    fgets(buffer, 500, stdin);

    if (!strchr(buffer, '\n'))
    {
       while (fgetc(stdin) != '\n');
    }

    if (strcmp (buffer, "\\quit\n") == 0)
    {
       close(client_fd);
       return 1;
    }
    n = write(client_fd, buffer, strlen(buffer));
    if (n < 0)
    {
        error("ERROR writing to socket");
    }

    memset(buffer, 0, 501);
}

1 个答案:

答案 0 :(得分:0)

select用于检查套接字是否已准备好读取或写入。如果它是阻塞读取则表示没有要读取的数据。如果它在写入时阻塞,则表示TCP缓冲区可能已满,远程端必须读取一些数据,以便套接字允许写入更多数据。由于select块直到其中一个套接字描述准备就绪,你还需要在select中使用timeout来避免等待很长时间。

在您的特定情况下,如果您的远程/接收端继续从套接字读取数据,则select将不会阻止另一端的写入。否则tcp缓冲区将在发送方侧变满,select将阻塞。发布的答案也表明处理EAGAIN或EWOULDBLOCK的重要性。

样本流程:

while(bytesleft > 0)
then
    nbytes = write data
    if(nbytes > 0)
      bytesleft -= nbytes;
    else
      if write returns with EAGAIN or EWOULDBLOCK
        call poll or select to wait for the socket to be come ready
       endif
    endif
    if poll or select times out
       then handle the timeout error(e.g. the remote end did not send the
                                      data within expected time interval)
    endif
end while

代码还应包括句柄错误条件和读/写返回(例如,写入/读取返回0)。另请注意,read / recv返回0表示远程端关闭了套接字。