Читаем Linux: Полное руководство полностью

 /* Ports less than this value are reserved

    for privileged processes. */

 IPPORT_RESERVED = 1024,

 /* Ports greater this value are reserved

    for (non-privileged) servers. */

 IPPORT_USERRESERVED = 5000

};

Нам понадобятся сразу два сокета: первый — это сокет сервера, а через второй сокет мы будем производить обмен данными с клиентом.

int sock1, sock2;

Следующие переменные: ans_len используется для хранения размера передаваемой клиентом информации — фактического размера структуры struct sockaddr_in, а total — это счетчик числа клиентов, используемый для вывода порядкового номера клиента.

Переменная buffer размера BUF_SIZE — это наш буфер для обмена информацией. Нам нужны две структуры типа sockaddr_in — одна для сервера (sin) и одна для клиента (client).

В строке

sock1 = socket(AF_INET, SOСK_STREAM, 0);

мы создаем наш, «серверный», сокет: набор протоколов — TCP/IP, режим — с установлением соединения.

Затем мы инициализируем структуру sin:

memset((char *)&sin, '\0', sizeof(sin));

sin.sin_family = AF_INET; // TCP/IP

sin.sin_addr.s_addr = INADDR_ANY; // можем работать на

                                  // любом адресе

sin.sin_port = SERVER_PORT; // указываем порт (1234)

После создания сокета и инициализации структуры sin, нужно связать наш сокет с адресом и портом сервера:

bind(sock1, (struct sockaddr *)&sin, sizeof(sin));

Оператор listen(sock1, 3) означает, что мы будем прослушивать сокет sock1 (порт 1234) и максимальное число клиентов не должно превышать 3.

Как и любой нормальный сервер, мы должны работать в бесконечном цикле, постоянно обрабатывая запросы клиентов. В бесконечном цикле мы:

1. получаем размер структуры client

ans_len = sizeof(client);

2. создаем сокет sock2, через который будем обмениваться данными с клиентом. Если в очереди listen нет клиентов, мы переходим в состояние ожидания

sock2 = accept(sock1, &client, &ans_len);

3. как только подключится клиент, мы отправим ему сообщение MSG_TO_SEND

write(sock2, MSG_TO_SEND, sizeof(MSG_TO_SEND));

4. увеличиваем счетчик клиентов

total+=1;

5. получаем размер прочитанных данных, сами данные записываются в буфер buffer

ans_len = read(sock2, buffer, BUF_SIZE);

6. выводим прочитанные данные на стандартный вывод

write(1, buffer, ans_len);

7. завершаем сеанс связи

shutdown(sock2, 0);

8. закрываем сокет

close(sock2);

Конечно, любой нормальный сервер при поступлении определенных сигналов, например, SIG_HUP, должен корректно перезапуститься или вообще завершить работу. Наш сервер этого не делает — обработку сигналов, я надеюсь, вы можете добавить сами.

Теперь мы можем откомпилировать нашу программу:

$ gcc -о server server.c

Запускаем:

./server

Программа перешла в состояние ожидания новых клиентов.

<p>27.3.8. Программа-клиент</p>

Программа-клиент несколько проще, чем сервер. Вот ее листинг:

Листинг 27.4. Программа-клиент

#include

#include

#include

#include

#include

#include

#define SERVER_HOST "localhost"

#define SERVER_PORT 1234

#define CLIENT_PORT 1235

#define MSG "Denis\n"

main() {

 int sock;

 int ans_len;

 int BUF_SIZE = 64;

 char buffer[BUF_SIZE];

 struct hostent *h;

 struct sockaddr_in client, server;

 sock = socket(AF_INET, SOCK_STREAM, 0);

 memset((char *)&client, '\0', sizeof(client));

 client.sin_family = AF_INET;

 client.sin_addr.s_addr = INADDR_ANY;

 client.sin_port = CLIENT_PORT;

 bind(sock, (struct sockaddr *)&client, sizeof(client));

 memset((char *)&client, '\0', sizeof(server));

 h = gethostbyname(SERVER_HOST);

 server.sin_family = AF_INET;

 memcpy((char *)&server.sin_addr.h->h_addr, h->h_length);

 server.sin_port = SERVER_PORT;

Перейти на страницу:

Все книги серии Полное руководство

Похожие книги