Рассмотрим часть серверной программы, обрабатывающей запрос по TCP. Допустим, что обработка данных (пусть вместе с обратной отсылкой) осуществляется в функции make(string buff).
bind(s, (sockaddr*)&serv_addr, nsize));
listen(s, 2);
sender_sock = accept(s, (sockaddr*)&sender, &nsize);
recv(sender_sock, &buff[0], sizeof(buff), 0);
make(buff);
closesocket(s);
WSACleanup();
Такая программа получает один запрос от клиента, выполянет необходимые действия и завершает свою работу.
Чтобы сервер не завершал работу после одного запроса, необходимо задать цикл:
bind(s, (sockaddr*)&serv_addr, nsize));
while(1){
listen(s, 2);
sender_sock = accept(s, (sockaddr*)&sender, &nsize);
recv(sender_sock, &buff[0], sizeof(buff), 0);
make(buff);
if(WSAGetLastError()) break;
}
closesocket(s);
WSACleanup();
Такая программа, выполнив обработку одного запроса, возвращает управление функции listen и ожидает нового запроса.
Разумеется, вместо возникновения ошибки можно задать любое другое условие прерывания.
Теперь вопрос: как заставить сервер слушать новые запросы, не дожидаясь обработки предыдщего?
Одним из возможных решений этой задачи является использование дочерних потоков процесса через вызов функции CreateThread:
CreateThread(
NULL, // аттрибуты безопасности, значчение по умолчанию.
0, // рамер стека потока, значение по умолчанию.
ThreadProc, // функция, которая будет выполняться в потоке
pData, // структура, в которую заносятся параметры функции ThreadProc
0, // флаги
&ThreadId); // идентификатор потока
В применении к нашей программе это будет выглядеть так (для выделения памяти не забываем подключать malloc.h):
typedef struct {
сhar* buff;
SOCKET s;
} *my_data;
DWORD ThreadProc(LPVOID params){
my_data data;
data = (my_data)params;
buff = data->buff;
s = data->s;
recv(sender_sock, &buff[0], sizeof(buff), 0);
make(buff);
}
void main(){
**********************************
**********************************
my_data pData = (my_data)malloc(sizeof(my_data));
DWORD ThreadId[N];
bind(s, (sockaddr*)&serv_addr, nsize));
ThreadNum = 0;
while(1){
listen(s, 2);
sender_sock = accept(s, (sockaddr*)&sender, &nsize);
pData->s = sеnder_sock;
pData->buff = buff;
CreateThread(NULL, 0 ,(LPTHREAD_START_ROUTINE)& ThreadProc, pData, 0, &ThreadId[ThreadNum]);
ThreadNum++;
if(WSAGetLastError()) break;
}
closesocket(s);
WSACleanup();
}
Сервер принимает запрос, извлекаетиз него данные клиента, после чего передает копии переменных sender_sock и buff в новый поток. В новом потоке выполняется обработка запроса, в товремя как цикл возвращается к прослушиванию сети. После обработки запроса поток закрывается и использованная им память очищается.
1) Клиент вводит строку с клавиатуры и отсылает ее серверу.
2) Сервер принимает сообщение, обрабатывает его некоторым образом (например, инвертирует) и отсылает результат клиенту
3) Клиент принимает результат и выводит его на экран.
Требования:
- все функции, которые могут возвращать значение ошибки, должны обрабатываться (ошибки отлавливаются, выводится источник ошибки и ее номер).
- работа приложения должна быть видна (чтобы не было вопросов "А как мне понять, что программа работает?").
Допускается сдача пары клиент/сервер на двоих.
1) Клиент <--> Клиент
Клиенту задается адрес*, с которым он связывается.
Вводится имя, под которым он будет виден другим пользователям.
Клиент в цикле вводит строки с клавиатуры. Строка "quit" (или любая другая, но пользователь должен быть предупрежден) означает выход из приложения.
К введенной строке добавляется имя в формате "имя: строка" и пересылается по адресу*.
Другой клиент принимает эту строку и выводит на экран.
Соответственно, кроме ввода с клавиатуры, клиент в цикле принимает сообщения от произвольного клиента.
Должны быть реализованы "приветственное" сообщение (например, "имя enter the room") и "прощальное" сообщение.
2) Сервер
Имеет структуру данных (массив) для запоминания адресов подключенных к нему клиентов.
Принимает сообщение от произвольного клиента и передает его по всему списку клиентов, кроме отправителя.
Для добавления/удаления адреса в список используются приветственные/прощальные сообщения.
Допускается сдача пары клиент/сервер на двоих.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.