bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
4. Создайте очередь запросов на соединение и ждите запроса клиента:
listen(server_sockfd, 5);
while(1) {
char ch;
printf("server waiting\n");
5. Примите запрос на соединение:
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,
(struct sockaddr *)&client_address, &client_len);
6. Читайте и записывайте данные клиента с помощью client_sockfd
:
read(client_sockfd, &ch, 1);
ch++;
write(client_sockfd, &ch, 1);
close(client_sockfd);
}
}
Как это работает
В этом примере серверная программа в каждый момент времени может обслуживать только одного клиента. Она просто читает символ, поступивший от клиента, увеличивает его и записывает обратно. В более сложных системах, где сервер должен выполнять больше работы по поручению клиента, такой подход будет неприемлемым, потому что другие клиенты не смогут подключиться до тех пор, пока сервер не завершит работу. Позже вы увидите пару методов, позволяющих подключаться многочисленным клиентам.
Когда вы выполняете серверную программу, она создает сокет и ждет запросов на соединение. Если вы запустите ее в фоновом режиме, т.е. она будет выполняться независимо, вы сможете затем запускать клиентов как высокоприоритетные задачи.
$ ./server1 &
[1] 1094
$ server waiting
Ожидая запросы на соединения, сервер выводит сообщение. В приведенном примере сервер ждет запрос с сокета файловой системы, и вы сможете увидеть его с помощью обычной команды ls
.
Хорошо взять за правило удалять сокет после окончания работы с ним, даже в случае аварийного завершения программы из-за получения сигнала. Это убережет файловую систему от загромождения неиспользуемыми файлами.
$ ls -lF server socket
srwxr-xr-x 1 neil users 0 2007-06-23 11:41 server_socket=
Здесь тип устройства — сокет, на что указывает символ s
перед правами доступа и символ =
в конце имени. Сокет был создан как обычный файл с правами доступа, модифицированными текущей umask
. Если применить команду ps
, то можно увидеть сервер, выполняющийся в фоновом режиме. Он показан спящим (параметр STAT
равен s
) и, следовательно, не потребляющим ресурсы ЦП.
$ ps lх
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
0 1000 23385 10689 17 0 1424 312 361800 S pts/1 0:00 ./server1
Теперь, когда вы запустите программу, то успешно подключитесь к серверу. Поскольку сокет сервера существует, вы можете соединиться с ним и обмениваться данными.
$ ./client1
server waiting char from server = В
$
На терминале вывод сервера и клиента перемешаны, но можно увидеть, что сервер получил символ от клиента, увеличил его и вернул. Далее сервер продолжает выполняться и ждет следующего клиента. Если вы запустите несколько клиентов вместе, они будут обслуживаться по очереди, хотя полученный вывод может оказаться еще более перемешанным.
$ ./client1 & ./client1 & ./client1 &
[2] 23412
[3] 23413
[4] 23414
server waiting
char from server = В
server waiting
char from server = В
server waiting
char from server = В
server waiting
[2] Done client1
[3]- Done client1
[4]+ Done client1
$
Атрибуты сокета
Для того чтобы до конца понять системные вызовы, применявшиеся в рассмотренном примере, необходимо узнать кое-что об организации сети в системах UNIX.
Сокеты характеризуются тремя атрибутами:
Домены задают сетевую рабочую среду, которую будет использовать соединение сокетов. Самый популярный домен сокетов — AF_INET
, ссылающийся на сеть Интернет и применяемый во многих локальных сетях Linux и, конечно, в самом Интернете. Низкоуровневый протокол Internet Protocol (IP), у которого только одно адресное семейство, накладывает определенный способ задания компьютеров, входящих в сеть. Он называется