2014-04-24 73 views
0

我正在使用GUI編寫單個聊天程序。我想寫一個可以接受許多客戶端的服務器。每個客戶都可以連接成功。但是,發送和接收數據存在一個奇怪的問題。我使用select()和一個線程同時處理多個套接字。如果客戶端發送一些數據給服務器,它會收到它並將其發送回該客戶端(特別是客戶端沒有「預測」)。但是服務器不會將它進一步發送給另一個客戶端(比如每個客戶端都與服務器有私人對話)。這裏是我的代碼:C++ winsock - 服務器只與單個客戶端通信,而它應該與每個客戶端通信

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

       } 
      } 
     } 
    } 
} 

回答

0

你只將數據發送到客戶衛生組織fd是在readfd,也就是隻對一個剛剛傳達給你。嘗試改爲測試FD_ISSET(j, mainfd)

+0

的工作,非常感謝你! – user3366592

0

此代碼無效,在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); 
       } 
      } 
     } 
    } 
}