Книга: TCP/IP Архитектура, протоколы, реализация (включая IP версии 6 и IP Security)
21.8 Более простой сервер
21.8 Более простой сервер
Многие серверы разрабатываются как в показанном выше примере. Однако можно использовать более упрощенную модель, когда сервер должен выполнять только простые запросы клиента (см. ниже).
Вместо создания дочернего процесса для каждого клиента сервер может непосредственно выполнять запрос, а затем закрывать соединение. Очередь сервера позволяет нескольким другим клиентам ожидать, пока он не будет готов обработать их запросы.
Ниже приведен листинг для более простого сервера. К этому серверу клиенты также могут обращаться через рассмотренную выше программу tcpclient.
/* tcpsimp.c
* Для запуска программ ввести "tcpsimp" */
/* Сначала включить стандартные заголовочные файлы. */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
main() {
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: Номер порта %dn", 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 для клиента %dn", sockClient);
printf("SERVER: Длина сообщения %dn", msgLength);
printf("SERVER: Сообщение: %snn", buf);
}
- 21.1 Введение
- 21.2 Службы socket
- 21.3 Блокированные и неблокированные вызовы
- 21.4 Вызовы socket
- 21.5 Программирование работы TCP socket
- 21.6 Серверная программа TCP
- 21.7 Клиентская программа TCP
- 21.8 Более простой сервер
- 21.9 Интерфейс программирования socket для UDP
- 21.10 Программа сервера UDP
- 21.11 Клиентская программа UDP
- 21.12 Дополнительная литература
- 19.7.3. Сервер WEBrick
- 1.2. Простой клиент времени и даты
- Запуск InterBase-сервера
- Расширенная установка InterBase-сервера
- Совместимость клиентов и серверов различных версий
- СТРУКТУРА ПРОСТОЙ ПРОГРАММЫ
- Статистика InterBase-сервера
- Сервер для InterBase
- 1.3.3. Достоинства и недостатки анонимных прокси-серверов
- Минимальный состав сервера InterBase SuperServer
- ПРИМЕР ПРОСТОЙ ПРОГРАММЫ НА ЯЗЫКЕ СИ
- Отличительные особенности сервера Yaffil