1

2010年にstackoverflowメンバーatanosによって作成された、複数のクライアントを単一のサーバーに接続するプログラムをチェックしていました。コマンドラインから接続の詳細を受け入れるように彼のプログラムを少し変更しました。以下はサーバーとcientコードです。

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;
}

Client.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);
}

サーバーが複数の接続を受け入れることがわかりますが、いずれかのクライアントからメッセージを送信すると、サーバーのrecvAPIは何も読み取りません。クライアントでのsendAPIは成功し、すべての文字が送信されたことがわかります。誰かコメントしてもらえますか?

4

2 に答える 2

2

問題は、クライアント接続を実際に読み取りに入れていないことですfd_set

この線:

readfds = fds;

readfdsサーバー(リスニング)ソケットのみが含まれている状態にリセットされます。ループを実行するたびに、fd_setを呼び出す前に、各クライアントファイル記述子を完全に再設定する必要があります。select

他の問題である可能性があります(これは多くのコードを通過する必要があります)が、最も可能性の高い問題のようです。

(ところで、割り当てが合法かどうかはわかりません。実装にfd_set単純でコピー可能な構造体である必要はないと思います。)

于 2012-09-02T18:48:38.263 に答える
1

コードに複数のエラーがありました。selectcallを正しく使用していませんでした。selectの最初の引数は、リッスンしているfdsの最大数に1を加えたものになります。2番目の引数には、監視するfdsのリストが含まれます。

FD_SETSIZEをfdmaxに置き換えました。コードの問題を修正し、以下に貼り付けました。

  8 int main(int argc, char **argv)
  9 {
 10   fd_set fds, readfds;
 11   int i, clientaddrlen, portno;
 12   int clientsock[2], rc, numsocks = 0, maxsocks = 2;
 13   int fdmax=0;
 14
 15   if (argc < 2){
 16       fprintf(stderr,"ERROR, no port provided\n");
 17       exit(1);
 18   }
 19
 20   int serversock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 21
 22   if (serversock == -1) perror("Socket");
 23
 24   portno = atoi(argv[1]);
 25   struct sockaddr_in serveraddr, clientaddr;
 26   bzero(&serveraddr, sizeof(struct sockaddr_in));
 27   serveraddr.sin_family = AF_INET;
 28   serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
 29   serveraddr.sin_port = htons(portno);
 30
 31   if (-1 == bind(serversock, (struct sockaddr *)&serveraddr,sizeof(struct sockaddr_in))) perror("Bind");
 32
 33   if (-1 == listen(serversock, SOMAXCONN)) perror("Listen");
 34
 35   FD_ZERO(&fds);
 36   FD_SET(serversock, &fds);
 37   fdmax = serversock;
 38
 39   clientaddrlen = sizeof(clientaddr);
 40   while(1) {
 41     readfds = fds;
 42     rc = select(fdmax + 1, &readfds, NULL, NULL, NULL);
 43
 44     if (rc == -1){
 45       perror("Select");
 46       break;
 47    }
 48
 49     for (i = serversock; i <= fdmax; i++)
 50     {
 51       if (FD_ISSET(i, &readfds)){
 52         if (i == serversock){
 53           if (numsocks < maxsocks){
 54             clientsock[numsocks] = accept(serversock,(struct sockaddr *) &clientaddr,
 55                 (socklen_t *)&clientaddrlen);
 56
 57             if (clientsock[numsocks] == -1) perror("Accept");
 58             else printf("Connection accepted\n");
 59
 60             FD_SET(clientsock[numsocks], &fds);
 61             fdmax = clientsock[numsocks];
 62              numsocks++;
 63           }
 64           else
 65             printf("Ran out of socket space.\n");
 66         }
 67         else
 68         {
 69           int messageLength = 100;
 70           char message[messageLength+1];
 71           int numOfChRead, index = 0, limit = messageLength+1;
 72
 73           numOfChRead = recv(i, message, messageLength,0);
 74
 75           if(numOfChRead > 0)
 76               printf("Data Received !!! length: %d Message: %s", numOfChRead, message);
 77           else
 78               printf("Nothing read\n");
 79         }
 80       }
 81     }
 82   }
 83   close(serversock);
 84   return 0;
 85 }
于 2012-09-02T20:04:44.417 に答える