Для сокета на уровне UDP происходит неявная буферизация дейтаграмм в виде очереди. Действительно, у каждого сокета UDP имеется буфер приема, и каждая дейтаграмма, приходящая на этот сокет, помещается в его буфер приема. Когда процесс вызывает функцию recvfrom
SO_RCVBUF
в разделе 7.5.На рис. 8.3 показано обобщение нашей модели TCP клиент-сервер из главы 5, когда два клиента устанавливают соединения с сервером.
Рис. 8.3
. Обобщение модели TCP клиент-сервер с двумя клиентамиЗдесь имеется два присоединенных сокета, и каждый из присоединенных сокетов на узле сервера имеет свой собственный буфер приема. На рис. 8.4 показан случай, когда два клиента отправляют дейтаграммы серверу UDP.
Рис. 8.4
. Обобщение модели UDP клиент-сервер с двумя клиентамиСуществует только один процесс сервера, и у него имеется один сокет, на который сервер получает все приходящие дейтаграммы и с которого отправляет все ответы. У этого сокета имеется буфер приема, в который помещаются все приходящие дейтаграммы.
Функция main
AF_INET
, а затем выделяет и инициализирует структуру адреса сокета IPv4), но функция dg_echo
от протокола не зависит. Причина, по которой функция dg_echo
не зависит от протокола, заключается в том, что вызывающий процесс (в нашем случае функция main
) должен разместить в памяти структуру адреса сокета корректного размера, и указатель на эту структуру вместе с ее размером передаются в качестве аргументов функции dg_echo
. Функция dg_echo
никогда не углубляется в эту структуру: она просто передает указатель на нее функциям recvfrom
и sendto
. Функция recvfrom
заполняет эту структуру, вписывая в нее IP-адрес и номер порта клиента, и поскольку тот же указатель (pcliaddr
) затем передается функции sendto
в качестве адреса получателя, таким образом дейтаграмма отражается обратно клиенту, отправившему дейтаграмму.8.5. Эхо-клиент UDP: функция main
Функция main
Листинг 8.3
. Эхо-клиент UDP//udpcliserv/udpcli01.c
1 #include "unp.h"
2 int
3 main(int argc, char **argv)
4 {
5 int sockfd;
6 struct sockaddr_in servaddr;
7 if (argc != 2)
8 err_quit("usage: udpcli
9 bzero(&servaddr, sizeof(servaddr));
10 servaddr.sin_family = AF_INET;
11 servaddr.sin_port = htons(SERV_PORT);
12 Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
13 sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
14 dg_cli(stdin, sockfd, (SA*)&servaddr, sizeof(servaddr));
15 exit(0);
16 }
9-12
dg_cli
. Она определяет, куда отправлять дейтаграммы.13-14
dg_cli
.8.6. Эхо-клиент UDP: функция dg_cli
В листинге 8.4 показана функция dg_cli
Листинг 8.4
. Функция dg_cli: цикл обработки клиента//lib/dg_cli.c
1 #include "unp.h"
2 void
3 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
4 {
5 int n;
6 char sendline[MAXLINE], recvline[MAXLINE + 1];
7 while (Fgets(sendline, MAXLINE, fp) != NULL) {
8 Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
9 n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
10 recvline[n] = 0; /* завершающий нуль */
11 Fputs(recvline, stdout);
12 }
13 }