Литмир - Электронная Библиотека
Содержание  
A
A

 9   err_quit("usage: udpcli <Ipaddress>");

10  sockfd = Socket(AF_INET, SOCK_DGRAM, 0);

11  bzero(&servaddr, sizeof(servaddr));

12  servaddr.sin_family = AF_INET;

13  servaddr.sin_port = htons(SERV_PORT);

14  Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

15  Connect(sockfd, (SA*)&servaddr, sizeof(servaddr));

16  len = sizeof(cliaddr);

17  Getsockname(sockfd, (SA*)&cliaddr, &len);

18  printf("local address %s\n", Sock_ntop((SA*)&cliaddr, len));

19  exit(0);

20 }

Если мы запустим программу на узле

freebsd
с несколькими сетевыми интерфейсами, то получим следующий вывод:

freebsd % <b>udpcli09 206.168.112.96</b>

local address 12.106.32.254:52329

freebsd % <b>udpcli09 192.168.42.2</b>

local address 192.168.42.1:52330

freebsd % <b>udpcli09 127.0.0.1</b>

local address 127.0.0.1:52331

По рис. 1.7 видно, что когда мы запускаем программу первые два раза, аргументом командной строки является IP-адрес в разных сетях Ethernet. Ядро присваивает локальный IP-адрес первичному адресу интерфейса в соответствующей сети Ethernet. При вызове функции

connect
на сокете UDP ничего не отправляется на этот узел — это полностью локальная операция, которая сохраняет IP-адрес и порт собеседника. Мы также видим, что вызов функции connect на неприсоединенном сокете UDP также присваивает сокету динамически назначаемый порт.

ПРИМЕЧАНИЕ

К сожалению, эта технология действует не во всех реализациях, что особенно касается ядер, происходящих от SVR4. Например, это не работает в Solaris 2.5, но работает в AIX, Digital Unix, Linux, MacOS X и Solaris 2.6.

8.15. Эхо-сервер TCP и UDP, использующий функцию select

Теперь мы объединим наш параллельный эхо-сервер TCP из главы 5 и наш последовательный эхо-сервер UDP из данной главы в один сервер, использующий функцию

select
для мультиплексирования сокетов TCP и UDP. В листинге 8.14 представлена первая часть этого сервера.

Листинг 8.14. Первая часть эхо-сервера, обрабатывающего сокеты TCP и UDP при помощи функции select

//udpcliserv/udpservselect01.c

 1 #include &quot;unp.h&quot;

 2 int

 3 main(int argc, char **argv)

 4 {

 5  int listenfd, connfd, udpfd, nready, maxfdp1;

 6  char mesg[MAXLINE];

 7  pid_t childpid;

 8  fd_set rset;

 9  ssize_t n;

10  socklen_t len;

11  const int on = 1;

12  struct sockaddr_in cliaddr, servaddr;

13  void sig_chld(int);

14  /* создание прослушиваемого сокета TCP */

15  listenfd = Socket(AF_INET, SOCK_STREAM, 0);

16  bzero(&amp;servaddr, sizeof(servaddr));

17  servaddr.sin_family = AF_INET;

18  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

19  servaddr.sin_port = htons(SERV_PORT);

20  Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &amp;on, sizeof(on));

21  Bind(listenfd, (SA*)&amp;servaddr, sizeof(servaddr));

22  Listen(listenfd, LISTENQ);

23  /* создание сокета UDP */

24  udpfd = Socket(AF_INET, SOCK_DGRAM, 0);

25  bzero(&amp;servaddr, sizeof(servaddr));

26  servaddr.sin_family = AF_INET;

27  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

28  servaddr.sin_port = htons(SERV_PORT);

29  Bind(udpfd, (SA*)&amp;servaddr, sizeof(servaddr));

Создание прослушиваемого сокета TCP

14-22
 Создается прослушиваемый сокет TCP, который связывается с заранее известным портом сервера. Мы устанавливаем параметр сокета
SO_REUSEADDR
в случае, если на этом порте существуют соединения.

Создание сокета UDP

23-29
 Также создается сокет UDP и связывается с тем же портом. Даже если один и тот же порт используется для сокетов TCP и UDP, нет необходимости устанавливать параметр сокета
SO_REUSEADDR
перед этим вызовом функции
bind
, поскольку порты TCP не зависят от портов UDP.

В листинге 8.15 показана вторая часть нашего сервера.

Листинг 8.15. Вторая половина эхо-сервера, обрабатывающего TCP и UDP при помощи функции select

udpcliserv/udpservselect01.c

30  Signal(SIGCHLD, sig_chld); /* требуется вызвать waitpid() */

31  FD_ZERO(&amp;rset);

32  maxfdp1 = max(listenfd, udpfd) + 1;

33  for (;;) {

34   FD_SET(listenfd, &amp;rset);

35   FD_SET(udpfd, &amp;rset);

36   if ((nready = select(maxfdp1, &amp;rset, NULL, NULL, NULL)) &lt; 0) {

37    if (errno == EINTR)

105
{"b":"225366","o":1}