c - "recv"即使已接受连接也无法正常工作

标签 c sockets unix

我查看了 stackoverflow 成员 atanos 在 2010 年编写的关于将多个客户端连接到单个服务器的程序,我稍微修改了他的程序以接受来自命令行的连接详细信息,下面是服务器和代码。

Server.c

int main(int argc, char **argv)
{
  fd_set fds, readfds;
  int i, clientaddrlen, portno;
  int clientsock[2], rc, numsocks = 0, maxsocks = 2;

  if (argc < 2){
      fprintf(stderr,"ERROR, no port provided\n");
      exit(1);
  }

  int serversock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  if (serversock == -1) perror("Socket");

  portno = atoi(argv[1]);
  struct sockaddr_in serveraddr, clientaddr;
  bzero(&serveraddr, sizeof(struct sockaddr_in));
  serveraddr.sin_family = AF_INET;
  serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
  serveraddr.sin_port = htons(portno);

  if (-1 == bind(serversock, (struct sockaddr *)&serveraddr,sizeof(struct sockaddr_in))) perror("Bind");

  if (-1 == listen(serversock, SOMAXCONN)) perror("Listen");

  FD_ZERO(&fds);
  FD_SET(serversock, &fds);

  while(1) {
    readfds = fds;
    rc = select(FD_SETSIZE, &readfds, NULL, NULL, NULL);

    if (rc == -1){
      perror("Select");
      break;
   }

    for (i = 0; i < FD_SETSIZE; i++)
    {
      if (FD_ISSET(i, &readfds)){
        if (i == serversock){
          if (numsocks < maxsocks){
            clientsock[numsocks] = accept(serversock,(struct sockaddr *) &clientaddr,
                (socklen_t *)&clientaddrlen);

            if (clientsock[numsocks] == -1) perror("Accept");
            else printf("Connection accepted\n");

            FD_SET(clientsock[numsocks], &fds);
             numsocks++;
          }
          else
            printf("Ran out of socket space.\n");
        }
        else
        {
          int messageLength = 10;
          char message[messageLength+1];
          int numOfChRead, index = 0, limit = messageLength+1;

          numOfChRead = recv(clientsock[i], message, messageLength,0);

          if(numOfChRead > 0)
              printf("Data Received !!! length: %d Message: %s", numOfChRead, message);
          else
              printf("Nothing read\n");
        }
      }
    }
  }
  close(serversock);
  return 0;
}

客户端.c

int main(int argc, char **argv)
{
  struct sockaddr_in servaddr;
  struct hostent *server;
  int portno, bytesSent = 0;

  if (argc < 3){
      fprintf(stderr,"Usage %s hostname port\n", argv[0]);
      exit(0);
  }

  portno = atoi(argv[2]);
  int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (sock == -1) perror("Socket");

  server = gethostbyname(argv[1]);

  if (server == NULL){
      fprintf(stderr,"ERROR, no such host\n");
      exit(0);
  }

  bzero((void *) &servaddr, sizeof(servaddr));
  servaddr.sin_family = AF_INET;

  servaddr.sin_port = htons(portno);
  bcopy((char *)server->h_addr,(char *)&servaddr.sin_addr.s_addr,server->h_length);

  if (-1 == connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr))) perror("Connect");

  while(1) {
    char message[10];
    fgets(message, 10, stdin);
    message[10] = '\0';

    bytesSent = send(sock, message, strlen(message), 0);

    if(bytesSent == -1) printf("Sending failed with errno %d", errno);
    else printf("Sent %d characters", bytesSent);
  }
  close(sock);
}

我可以看到服务器接受多个连接,但是当我从任何客户端发送消息时,服务器中的 recv API 没有读取任何内容。客户端的发送 API 成功,我可以看到所有字符都已发送。有人可以发表评论吗?

最佳答案

问题是您实际上从未将客户端连接放入读取的 fd_set 中。

行:

readfds = fds;

readfds 重置为其中只有服务器(监听)套接字的状态。在每次循环调用 select 之前,您需要完全重新设置 fd_set 中的每个客户端文件描述符。

可能是其他问题(要处理大量代码),但这似乎是最有可能的问题。

(顺便说一句,我不确定赋值是否合法。我不认为对实现有任何要求 fd_set 是简单的、可复制的结构。)

关于c - "recv"即使已接受连接也无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12238713/

相关文章:

c - 在小型数据库程序中存储地址

c - 如何使用 clang 和安全堆栈标志编译可执行文件

c - sprintf 在 32 位 MCU 中通过中断重新进入 64 位操作

c++ - 套接字接收错误数据

java - Spring Integration 有状态 TCP 连接

linux - 在文件中查找搜索字符串并打印同一行中的下一个单词

c - 为什么 putchar 不需要 header ?

java - 写入速度比从套接字读取速度快

使用 libxml2 解析 xml 文件时 UNIX 中的 C++

linux - Makefile 在文件夹上循环并动态获取名称