Всем привет. Мне необходимо написать многопоточный чат. При написании, у меня возникла проблема. Я пишу по примеру из "Самоучитель игры на WinSock2". В книге приведен пример эхо-сервера, т.е. написать на его примере сервер для чата - не должно составить особой проблемы. Сейчас я нахожусь на стадии написания сервера. Возникла проблема с многопоточностью. В книге все просто: клиент коннектится к серверу а далее вызывается функция CreateThread с одним из параметров SexToClient, где SexToClient - функция, обслуживающая клиента. Вот код данной функции: Code: DWORD WINAPI SexToClient(LPVOID client_socket) { SOCKET my_sock; my_sock=((SOCKET *) client_socket)[0]; char buff[20*1024]; #define sHELLO "Hello, Sailor\r\n" // отправляем клиенту приветствие send(my_sock,sHELLO,sizeof(sHELLO),0); // цикл эхо-сервера: прием строки от клиента и возвращение ее клиенту while( (int bytes_recv=recv(my_sock,&buff[0],sizeof(buff),0)) && bytes_recv !=SOCKET_ERROR) send(my_sock,&buff[0],bytes_recv,0); // если мы здесь, то произошел выход из цикла по причине // возращения функцией recv ошибки – соединение с клиентом разорвано nclients++; // уменьшаем счетчик активных клиентов printf("disconnect\n"); PRINTNUSERS // закрываем сокет closesocket(my_sock); return 0; } Как отправлять сообщение пользователя не ему самому, а всем пользователям сразу? Я так понимаю, что надо как-то создать массив типа SOCKET, в котором будут хранится все сокеты, по которым подключены клиенты, и в цикле отправлять это сообщение всем, но как это сделать в потоке? Или может есть еще какие-нибудь варианты? P.S. Один поток обслуживает одного клиента. Максимальное число клиентов - 64. Подскажите, пожалуйста, решение этой проблемы. Спасибо.
Обычная структура многопоточного сервера: 1. Главная функция в цикле вызывает accept() 2. Принимает клиента, сохраняет сокет 3. Создает поток/процесс для клиента и передает ему сокет (его сокет) Получается, клиентский поток принимает только сокет, а для того, чтобы клиент имел доступ ко всем сокетам ты должен передать ему его сокет, и указатель на остальные сокеты. Создай примерно такую структуру : структура СТР{ клиентский_сокет; указатель_на_сокеты_других_клиентов; указатель_на_количество_подключенных_клиентов; }; Насчет "указатель_на_количество_подключенных_клиентов" можно сказать еще : 1. что это указатель, и количество клиентов может меняться, значит тут придеться использовать semaphor-ы или mutex-ы. 2. или можешь сделать так, чтобы каждый поток работал с 64 сокетами, но тут придеться проверять каждый сокет на "работо- спобность" Вот например для твоей проблемы примерно такой псевдокод : Code: struct STR { csocket cs; csocket *p_list; }; func main() { while( event()) { ListOfSocket[i] = AcceptClient(); if (OK) { STR * st = new STR; st->p_list = ListOfSocket; st->cs = ListOfSocket[i]; create_thread( client_thread_func(), st ); } } } func client_thread_func( STR *st ) { while( (buffer = getFromClient(st->cs))) { for (i = 0; i < 64; i++) { if (st->p_list[i] == OK) { SendToClient( buffer, st->p_list[i] ); } } } }
Сейчас у меня так и есть: Code: while((clientSocket=accept(servSocket, (sockaddr *) &clientAddr, &clientAddrSize))) { usersCount++; HOSTENT *host; host=gethostbyaddr((char *) &clientAddr.sin_addr.s_addr,4,AF_INET); // пытаемся получить имя хоста // выводим данные о клиенте cout<<host->h_name<<" ("<<inet_ntoa(clientAddr.sin_addr)<<" ) has connected")<<endl; PrintUsers(); DWORD threadID; CreateThread(NULL,NULL,ServeClient,&clientSocket,NULL,&threadID); } Далее для решения проблемы мне необходимо создать статический массив типа SOCKET (например он называется usersList) и проинициализировать все элементы значением INVALID_SOCKET. Далее, где у меня идет часть кода, с функцией accept сделать так: Code: while((clientSocket=accept(servSocket, (sockaddr *) &clientAddr, &clientAddrSize))) { usersList[usersCount]=clientSocket; usersCount++; А вот, что дальше делать с потоками я не очень понял. Не мог бы более подробней пояснить?
Ты наверное не понял что я написал: я ж говорил, что ты должен создать структуру и передать указатель на структура в новый созданный поток. Еще раз хорошенько прочти, то что я написал, там есть все что тебе нужно. p.s. Когда передалаешь код должен выглядеть примерно так : Code: CreateThread( NULL, NULL, ServeClient, [B]УКАЗАТЕЛЬ_НА_СТРУКТУРУ[/B] , NULL, &threadID);