我正在尝试在c ++套接字编程中构建多客户端服务器,我在多线程中发现了一些麻烦。我使用_beginthread来创建一些线程。当我们想要构建多客户端服务器时,我认为我们应该有一个可以随时使用循环来处理套接字接受的线程,到目前为止它工作正常(对我没有麻烦)。
之后我做了一些线程来处理 Client-DataReceiver ,我认为它比我们创建1个线程来处理所有客户端更好地交替循环整个客户端。多线程会因为它们同步工作而做得更好,我认为。
当我完成所有操作时,服务器的工作速度很慢/很难,甚至使用到100%的CPU使用率? 也许我的代码中有一些缺失/错误的东西?
void Initialize(){
[....Server initialize goes here...]
_beginthread( acceptNewClient, 0, (void*)1); //the thread that handle accepter
}
SOCKET ClientSocket;
void acceptNewClient(void* arg)
{
while(true){
ClientSocket = accept(ListenSocket,NULL,NULL);
if (ClientSocket != INVALID_SOCKET)
{
char value = 1;
setsockopt( ClientSocket, IPPROTO_TCP, TCP_NODELAY, &value, sizeof( value ) );
Client_Socket *client = new Client_Socket(ClientSocket);
_beginthread(ReceiveFromClient, 1,client ); //handle of client data receiver
client_list.push_back(client);
}
}
}
void ReceiveFromClient(void* client_sockets)
{
Client_Socket * client_socket = (Client_Socket*)client_sockets;
while(true){
server->doReceive();
}
}
修改
在弄清楚这种情况后,我认为这个问题是线程本身 我甚至尝试过新的控制台项目:#include <process.h>
void tes(void * arg){
while(true){
}
}
int _tmain(int argc, _TCHAR* argv[])
{
_beginthread( tes, 0, (void*)1);
_beginthread( tes, 0, (void*)1);
_beginthread( tes, 0, (void*)1);
_beginthread( tes, 0, (void*)1);
_beginthread( tes, 0, (void*)1);
_beginthread( tes, 0, (void*)1);
_beginthread( tes, 0, (void*)1);
_beginthread( tes, 0, (void*)1);
_beginthread( tes, 0, (void*)1);
_beginthread( tes, 0, (void*)1);
_beginthread( tes, 0, (void*)1);
_beginthread( tes, 0, (void*)1);
while(true){}
return 0;
}
线程对于计算机来说太难了,我认为错误就是线程本身。 那些代码确实使CPU 100%CPU,我的线程代码或解决方案是否有问题解决这种情况?
答案 0 :(得分:2)
正如我几个小时前暗示的那样,原因是你出于某种原因将套接字置于非阻塞模式,并且你没有使用select(),只是在recv()周围循环。它无论如何都没有意义,因为你每个连接使用一个线程。
根据你的回答,解决方案不是将套接字重新置于阻塞模式,而是首先删除设置非阻塞模式的代码,阻塞模式是默认的,正如@cHao指出的那样。
答案 1 :(得分:1)
100%CPU很可能是由while循环(while(true) server->doReceive();
)引起的。使用套接字的正确方法是在套接字上等待,直到有一些有用的东西要做。启用此功能的标准C ++函数是select
。
更高级的方法是使用I / O完成端口,但在您的阶段,该技术太先进,甚至可能根本不需要。
答案 2 :(得分:-1)
我发现了问题。首先,如果您想在每个客户端使用线程构建服务器,首先必须注意的是:
确保您事先使用ioctlsocket
将SOCKET设置为阻止模式
这实际上非常有意义! 好吧,当我们创建这样的线程时:
unsigned __stdcall threadFunc(void * arg)
{
while(1) {
}
return 0;
}
看起来如此简单的线程代码,但这是一个导致cpu工作如此困难的问题。 当recv winsocks的函数使用非阻塞模式调用时,它们将始终重复到while语句,当没有任何数据需要读取时,它们会像comp一样快速地旋转。当然这不是个好主意。 因此,如果我们想要克服它,当然正确的方法是:将套接字设置为非阻塞。
u_long iMode = 0;
iResult = ioctlsocket(ClientSocket, FIONBIO, &iMode);
当recv()被称为机器的Socket将等待,直到他们有一些字节要读。用这种方式'快速旋转'将不再发生
非常感谢..