【问题标题】:c++ winsock - server communicates only with single client while it should communicate with every clientc++ winsock - 服务器只与单个客户端通信,而它应该与每个客户端通信
【发布时间】:2014-04-24 20:18:20
【问题描述】:

我正在编写一个带有 GUI 的聊天程序。我想编写一个可以接受许多客户端的服务器。每个客户端都可以成功连接。但是发送和接收数据有一个奇怪的问题。我使用 select() 和一个线程同时处理多个套接字。如果客户端向服务器发送一些数据,它将接收它并将其发送回该客户端(客户端是特别编写的,没有“预测”)。但是服务器不会将其进一步发送给其他客户端(就像每个客户端都有自己与服务器的私人对话)。这是我的代码:

// this is rewritten from the Beej's tutorial with a little and insignificant changes
/* in the thread */
fd_set mainfd;
fd_set readfd;
// sin-size, newfd, maxfd - int
while(TRUE)
{
    readfd = mainfd;
    if(select(maxfd+1, &readfd, NULL, NULL, NULL) == -1)
    {
        MessageBoxA(NULL, "Error while trying to accept incoming connections (select)", "Error", 16);
        itoa(GetLastError(), buf, 10);
        MessageBoxA(NULL, buf, buf, 0);
        break;
    }
    for(int i = 0; i <= maxfd; i++)
    {
        char* psr;
        char srMsg[256];
        if(FD_ISSET(i, &readfd))
        {
            if(i == mainSocket)
            {
                sin_size = sizeof(their_addr);
                newfd = accept(mainSocket, (struct sockaddr*)&their_addr, &sin_size);
                if(newfd == SOCKET_ERROR)
                {
                    AddTextToEdit(hStaticChat, "* Error: couldn't accept incoming connection.", TRUE);
                }
                else
                {
                    FD_SET(newfd, &mainfd);
                    if(newfd > maxfd)
                    {
                        maxfd = newfd;
                    }

                }
            }
            else
            {
                len = recv(i, srMsg, 256, 0);
                if(len == 0 || len == SOCKET_ERROR)
                {
                    AddTextToEdit(hStaticChat, "* Client has disconnected", TRUE);
                    close(i);
                    FD_CLR(i, &mainfd);
                }
                else
                {
                        AddTextToEdit(hStaticChat, srMsg, TRUE);
                        for(int j = 0; j <= maxfd; j++)
                        {
                          if(FD_ISSET(j, &readfd))
                          {
                                  send(j, srMsg, len, 0);
                          }
                        }

                }
             }
        }
     }
}

【问题讨论】:

    标签: c++ sockets winsock


    【解决方案1】:

    您只是将数据发送给 fd 在readfd 中的客户端,也就是说,只发送给刚刚与您通信的那个客户端。尝试改为测试FD_ISSET(j, mainfd)

    【讨论】:

      【解决方案2】:

      此代码在 WinSock 下无效。 Windows 不像其他平台那样使用整数文件描述符来处理套接字。套接字使用实际的内核对象来表示,因此您不能将循环计数器用作套接字句柄等。还有 API 差异(closesocket() 而不是 close()maxfdselect() 忽略,FD_XXX() 期望 SOCKET 句柄而不是 int 等)。

      在 Windows 上,您需要改用类似的东西:

      fd_set mainfd;
      SOCKET newfd;
      int sin_size;
      ...
      
      while(TRUE)
      {
          fd_set readfd = mainfd;
          if (select(0, &readfd, NULL, NULL, NULL) == SOCKET_ERROR)
          {
              itoa(WSAGetLastError(), buf, 10);
              MessageBoxA(NULL, "Error while trying to accept incoming connections (select)", "Error", 16);
              MessageBoxA(NULL, buf, buf, 0);
              break;
          }
      
          for(int i = 0; i < readfd.fd_count; i++)
          {
              if (readfd.fd_array[i] == mainSocket)
              {
                  sin_size = sizeof(their_addr);
                  newfd = accept(mainSocket, (struct sockaddr*)&their_addr, &sin_size);
                  if (newfd == INVALID_SOCKET)
                  {
                      AddTextToEdit(hStaticChat, "* Error: couldn't accept incoming connection.", TRUE);
                  }
                  else
                  {
                      // Note that fd_set can only hold FD_SETSIZE (64) sockets as a time!
                      FD_SET(newfd, &mainfd);
                  }
              }
              else
              {
                  char srMsg[257];
      
                  len = recv(readfd.fd_array[i], srMsg, 256, 0);
                  if (len < 1)
                  {
                      if (len == 0)
                          AddTextToEdit(hStaticChat, "* Client has disconnected", TRUE);
                      else
                          AddTextToEdit(hStaticChat, "* Error: couldn't read from a client connection.", TRUE);
      
                      closesocket(readfd.fd_array[i]);
                      FD_CLR(readfd.fd_array[i], &mainfd);
                  }
                  else
                  {
                      srMsg[len] = 0;
                      AddTextToEdit(hStaticChat, srMsg, TRUE);
      
                      for (int j = 0; j < mainfd.fd_count; j++)
                      {
                          if (mainfd.fd_array[i] != mainSocket)
                              send(mainfd.fd_array[j], srMsg, len, 0);
                      }
                  }
              }
           }
      }
      

      【讨论】:

        猜你喜欢
        • 2023-04-05
        • 2011-09-11
        • 1970-01-01
        • 1970-01-01
        • 2017-07-16
        • 1970-01-01
        • 2016-10-04
        • 2011-08-18
        • 1970-01-01
        相关资源
        最近更新 更多