Я пытаюсь создать сервер нескольких клиентов в программировании сокетов c++, и я нашел некоторые проблемы в нескольких потоках. Я использую _beginthread для создания некоторых потоков. когда мы хотим построить многосерверный сервер, я думаю, что мы должны иметь поток, который обрабатывает сокет accepter в любое время с циклом, и пока он работает нормально (без проблем на мне).
после этого я делаю некоторые потоки для обработки Client-DataReceiver, и я думаю, что это лучше, чем мы создаем 1 поток для обработки всех клиентов с циклом для всех клиентов поочередно. Я думаю, что несколько потоков будут работать лучше, поскольку они работают синхронно.
когда я закончил все это, сервер работает так медленно/сложно, и они даже используют до 100% использования процессора? и, возможно, там что-то не хватает/неправильно в моем коде?
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();
}
}
Редактировать:
после выяснения этого случая, я думаю, что causer - это поток, который я даже попробовал в новом консольном проекте:
#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, есть ли что-то неправильное для моего кода потока или решения для решения этого случая?
Как я уже говорил несколько часов назад, причиной этого является то, что вы поместили свой сокет в неблокирующий режим по какой-то причине, и вы не используете select(), просто вращайте цикл вокруг recv(). Это не имеет никакого смысла, поскольку вы используете поток для каждого соединения.
Решение заключается не в том, чтобы перевести в режим блокировки в соответствии с вашим ответом, а в том, чтобы удалить код, который устанавливает режим неблокирования, в первую очередь, режим блокировки по умолчанию, как указано @cHao.
100% процессор, скорее всего, вызван while while (while(true) server->doReceive();
). Правильный способ использования сокетов - дождаться сокета, пока не будет сделано что-то полезное. Стандартная функция C++, которая позволяет это select
.
Более продвинутый подход будет заключаться в использовании портов завершения ввода-вывода, но на вашем этапе эта технология слишком продвинута и, возможно, даже не нужна.
я выяснил проблему. во-первых, если вы хотите создать сервер с потоком каждого клиента, первое, что нужно знать:
убедитесь, что вы предварительно установили режим блокировки в режим блокировки ioctlsocket
это на самом деле имеет смысл! ну, когда мы создавали поток вроде этого:
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, называемый машиной, будет ждать, пока не будет прочитано несколько байтов. таким образом, "быстрое формование" больше не будет
Спасибо, в любом случае..
ClientReceiver()
вызывает функцию сервера? Разве он не должен просто получать / отправлять, используя свой локальный сокет?