Шрифт:
int sockMain, sockClient, length, child;
struct sockaddr_in servAddr;
/* 1. Создать главный socket. */
if ( (sockMain = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Сервер не может открыть главный socket.");
exit(1);
}
/* 2. Ввести информацию в структуру данных, используемую для
* хранения локального IP-адреса и порта, "sin" в именах
* переменных — это сокращение от "socket internet". */
bzero((char *)&servAddr, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = 0;
/* 3. Вызвать bind, которая запишет используемый номер порта
* в servAddr. */
if (bind(sockMain, &servAddr, sizeof(servAddr)) ) {
perror("Вызов bind от сервера неудачен.");
exit(1);
}
/* 4. Чтобы узнать номер порта, следует использовать функцию
* getsockname для копирования порта в servAddr. */
length = sizeof(servAddr);
if (getsockname(sockMain, &servAddr, &length)) {
perror("Вызов getsockname неудачен.");
exit(1);
}
printf ("SERVER: Номер порта %d\n", ntohs(servAddr.sin_port));
/* 5. Установить очередь на пять клиентов.*/
listen(sockMain, 5);
/* 6. Ожидать поступления клиентов. Вызов accept возвратит
* дескриптор нового socket, который следует использовать клиенту. */
for(;;) {
if ((sockClient = accept(sockMain, 0, 0)) < 0) {
perror("Неверный socket клиента.");
exit(1);
}
/* 7. Обслужить клиента и закрыть соединение с ним. */
doTask(sockClient);
close(sockClient);
}
}
/* Читать один поступивший буфер, распечатать некоторую информацию
* и завершить работу. */
#define BUFLEN 81
int doTask(sockClient)
int sockClient;
{
char buf[BUFLEN];
int msgLength;
/* 8. Опустошение буфера и вызов recv
* для получения сообщения от клиента. */
bzero(buf, BUFLEN);
if ((msgLength = recv(sockClient,buf, 80, 0)) < 0) {
perror("Неверное получение." );
exit(1);
}
printf("SERVER: Socket для клиента %d\n", sockClient);
printf("SERVER: Длина сообщения %d\n", msgLength);
printf("SERVER: Сообщение: %s\n\n", buf);
}
21.9 Интерфейс программирования socket для UDP
Мы познакомились с наиболее общим интерфейсом программирования TCP. Теперь рассмотрим программирование сервера и клиента UDP. На рис. 21.3 показана схема диалога UDP между клиентом и сервером. Вызовы socket и bind быстро выполняются и немедленно возвращают ответ. Вызов recvfrom предполагает режим блокирования по умолчанию, который можно изменить на неблокированный (т.е. асинхронный) режим.
Рис. 21.3. Типичные программные вызовы в socket UDP
21.10 Программа сервера UDP
Показанная ниже программа создает socket для UDP, связывает вызов с портом, а затем получает и распечатывает сообщения, которые посылаются на этот порт:
/* udpserv.c
* Для запуска программы ввести "udpserv".
*
* Сначала включить стандартные заголовочные файлы. */