Дальше: Приложение B. Реализация протокола Вверх: socket Назад: 7.3 Имена хостов

Приложение А. Реализация протокола Daytime с использованием UDP

Протокол daytime определен в документе RFC867. Протокол может использовать в качестве транспортного протокола UDP и TCP. В случае использования UDP сервер занимает 13-й порт и ожидает поступления датаграмм. После получения датаграммы он отправляет назад строку содержащую текущие дату и время в произвольном формате.

Ниже приведен пример реализации серверной части daytime: #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <time.h> #include <string.h> main(){ int s, clen, rd, proto; struct sockaddr_in saddr, caddr; struct sockaddr *sa, *ca; struct hostent *rhost; time_t itime; char buf[2048], *tstr, *host; sa=&saddr; ca=&caddr; // Получаем номер протокола UDP proto=getprotobyname("udp")->p_proto; // Создаем сокет s=socket(PF_INET, SOCK_DGRAM, proto); if(s<0) { perror("udps: не удается создать сокет"); exit(1); } // Резервируем порт 13 saddr.sin_family=AF_INET; saddr.sin_addr.s_addr=INADDR_ANY; saddr.sin_port=htons(13); if(bind(s, sa, sizeof(saddr))==-1) { perror("udps: не удается занять порт"); exit(1); } caddr.sin_family=AF_INET; clen=sizeof(caddr); while(1) { // Ожидаем поступления запроса rd=recvfrom(s, buf, 1, 0, ca, &clen); if(rd==-1){ perror("udps: ошибка при получении данных"); exit(1); } // Преобразуем адрес хоста отправителя в его имя rhost=gethostbyaddr((char*)(&caddr.sin_addr), sizeof(caddr.sin_addr), AF_INET); if(h_errno){ printf("gethostbyaddr error: %d\n", h_errno); host=inet_ntoa(caddr.sin_addr); } else{ host=rhost->h_name; } // Получаем строку содержащую дату и время itime=time(NULL); tstr=ctime(&itime); // Выводим время поступления запроса, // адрес и порт отправителя printf("%s request from %s:%d\n", tstr, host, htons(caddr.sin_port)); // Отправляем дату и время клиенту sendto(s, tstr, strlen(tstr), 0, ca, sizeof(caddr)); } }

Реализация клиентской части приведена ниже. Клиент устанавливает ограничение на время ожидания поступления данных, посылает широковещательный запрос и ожидает поступления ответа. Получив ответ клиент выводит его на экран и ожидает поступления других ответов. Если функция recv завершается с ошибкой превышения времени ожидания ответа, то клиент считает что все ответы получены и завершает выполнение. #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <errno.h> #include <string.h> main(){ int s, so, clen, rd, proto; struct sockaddr_in saddr, caddr; struct sockaddr *sa, *ca; struct hostent *rhost; struct timeval timeout; char buf[100], *host; sa=&saddr; ca=&caddr; // Получаем номер протокола UDP proto=getprotobyname("udp")->p_proto; // Создаем сокет s=socket(AF_INET, SOCK_DGRAM, proto); if(s<0) { perror("udpc: не удается создать сокет"); exit(1); } // Разрешаем отпраку широковещательных пакетов so=1; rd=setsockopt(s,SOL_SOCKET,SO_BROADCAST,&so,sizeof(so)); if(rd==-1) { perror("udpc: не удается установить параметры сокета"); exit(1); } // Устанавливаем предельное время ожидания ответа timeout.tv_sec=3; timeout.tv_usec=0; rd=setsockopt(s,SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); if(rd==-1) { perror("udpc: не удается установить параметры сокета"); exit(1); } // Резервируем порт caddr.sin_family=AF_INET; caddr.sin_addr.s_addr=INADDR_ANY; caddr.sin_port=0; if(bind(s, ca, sizeof(caddr))==-1) { perror("udpc: не удается занять порт"); exit(1); } // Задаем адрес получателя saddr.sin_family=AF_INET; saddr.sin_port=htons(13); saddr.sin_addr.s_addr=INADDR_BROADCAST; clen=sizeof(saddr); // Отправляем запрос rd=sendto(s, buf, 1, 0, sa, clen); if(rd==-1){ perror("udpc: ошибка при отправке запроса"); exit(1); } while(1){ // Ожидаем ответ rd=recvfrom(s ,buf ,99 ,0 ,sa , &clen); if(rd==-1){ // Если превышено время ожидания ответа, то выход if(errno==EAGAIN) break; // Иначе ошибка perror("udpc: ошибка при получении ответа"); exit(1); } buf[rd]=(char)0; // Преобразуем адрес хоста отправителя в его имя rhost=gethostbyaddr((char*)(&saddr.sin_addr), sizeof(saddr.sin_addr), AF_INET); if(h_errno){ printf("gethostbyaddr error: %d",h_errno); host=inet_ntoa(caddr.sin_addr); } else{ host=rhost->h_name; } // Выводим информацию о поступившем ответе printf("%s - reply from %s\n", buf, host); } }



Zwon
2002-03-24