C++ Winsock服务器只与单个客户端通信,而应该与每个客户端通信。
我正在用GUI编写一个聊天程序。我想写一个可以接受许多客户机的服务器。每个客户端都可以成功连接。但在发送和接收数据方面存在一个奇怪的问题。我使用select和一个线程来同时处理多个套接字。如果客户机向服务器发送一些数据,它将接收数据并将其发送回该客户机。客户机是在没有预测的情况下编写的。但是服务器不会将它进一步发送到其他客户端,就像每个客户端都有自己与服务器的私人对话一样。这是我的密码:C++ Winsock服务器只与单个客户端通信,而应该与每个客户端通信。,c++,sockets,winsock,C++,Sockets,Winsock,我正在用GUI编写一个聊天程序。我想写一个可以接受许多客户机的服务器。每个客户端都可以成功连接。但在发送和接收数据方面存在一个奇怪的问题。我使用select和一个线程来同时处理多个套接字。如果客户机向服务器发送一些数据,它将接收数据并将其发送回该客户机。客户机是在没有预测的情况下编写的。但是服务器不会将它进一步发送到其他客户端,就像每个客户端都有自己与服务器的私人对话一样。这是我的密码: // this is rewritten from the Beej's tutorial with a l
// 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);
}
}
}
}
}
}
}
您只将数据发送给fd位于readfd中的客户机,也就是说,只发送给刚刚与您通信的客户机。尝试测试FD_ISSETj,改为mainfd。此代码在WinSock下无效。Windows不像其他平台那样使用整数文件描述符处理套接字。套接字使用实际的内核对象来表示,所以不能将循环计数器用作套接字句柄等。还有API差异closesocket代替close,maxfd被select忽略,FD_XXX expect套接字句柄代替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);
}
}
}
}
}