Чтение онлайн

ЖАНРЫ

Основы программирования в Linux
Шрифт:

1. В финальный пример программы server5.с вы включите заголовочные файлы sys/time.h и sys/ioctl.h вместо signal.h, использованного в предыдущей программе, и объявите несколько дополнительных переменных для работы с вызовом

select
:

#include <sys/types.h>

#include <sys/socket.h>

#include <stdio.h>

#include <netinet/in.h>

#include <sys/time.h>

#include <sys/ioctl.h>

#include <unistd.h>

#include <stdlib.h>

int main {

 int server_sockfd, client_sockfd;

 int server_len, client_len;

 struct sockaddr_in server_address;

 struct sockaddr_in client_address;

 int result;

 fd_set readfds, testfds;

2.

Создайте сокет для сервера и присвойте ему имя:

 server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

 server_address.sin_family = AF_INET;

 server_address.sin_addr.s_addr = htonl(INADDR_ANY);

 server_address.sin_port = htons(9734);

 server_len = sizeof(server_address);

 bind(serversockfd, (struct sockaddr *)&server_address, server_len);

3. Создайте очередь запросов на соединение и инициализируйте множество

readfds
для обработки ввода с сокета
server_sockfd
:

 listen(server_sockfd, 5);

 FD_ZERO(&readfds);

 FD_SET(server_sockfd, &readfds);

4. Теперь ждите запросы от клиентов. Поскольку вы передали пустой указатель как параметр

timeout
, не будет наступать истечения времени ожидания. Программа завершится и сообщит об ошибке, если
select
возвращает значение, меньшее 1.

 while(1) {

char ch;

int fd;

int nread;

testfds = readfds;

printf("server waiting\n");

result = select(FD_SETSIZE, &testfds, (fd_set *)0,

(fd_set *)0, (struct timeval *)0);

if (result < 1) {

perror("server5");

exit(1);

}

5. После того как вы определили, что есть активность, можно выяснить, какой из дескрипторов активен, проверяя каждый из них по очереди с помощью макроса

FD_ISSET
:

for (fd = 0; fd < FD_SETSIZE; fd++) {

if (FD_ISSET(fd, &testfds)) {

6. Если зафиксирована активность на

server_sockfd
, это может быть запрос на новое соединение, и вы добавляете в множество дескрипторов соответствующий
client_sockfd
:

if (fd == server_sockfd) {

client_len = sizeof(client_address);

client_sockfd = accept(server_sockfd,

(struct sockaddr*)&client_address, &client_len);

FD_SET(client_sockfd, &readfds);

printf("adding client on fd %d\n", client_sockfd);

}

Если

активен не сервер, значит, активность проявляет клиент. Если получен
close
, клиент исчезает, и можно удалить его из множества дескрипторов. В противном случае вы "обслуживаете" клиента, как и в предыдущих примерах.

else {

ioctl(fd, FIONREAD, &nread);

if (nread == 0) {

close(fd);

FD_CLR(fd, &readfds);

printf("removing client on fd %d\n", fd);

} else {

read(fd, &ch, 1);

sleep(5);

printf("serving client on fd %d\n", fd);

ch++;

write(fd, &ch, 1);

}

}

}

}

 }

}

Примечание

В реальную программу было бы неплохо вставить переменную, содержащую наибольший подключенный номер

fd
(необязательно самый последний подключенный номер
fd
). Это помешает просмотру в цикле тысяч номеров
fd
, которые даже не подсоединены и потенциально не могут быть готовы к чтению. Мы пропустили этот фрагмент кода для краткости и простоты примера.

При запуске этой версии сервера многочисленные клиенты будут обрабатываться последовательно в единственном процессе.

$ ./server5 &

[1] 26686

server waiting

$ ./client3 & ./client3 & ./client3 & ps x

[2] 26689

[3] 26690

adding client on fd 4

server waiting

[4] 26691

PID TTY STAT TIME COMMAND

26686 pts/1 S 0:00 ./server5

26689 pts/1 S 0:00 ./client3

26690 pts/1 S 0:00 ./client3

26691 pts/1 S 0:00 ./client3

26692 pts/1 R+ 0:00 ps x

$ serving client on fd 4

server waiting

adding client on fd 5

server waiting

adding client on fd 6

Поделиться с друзьями: