The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Каталог документации / Раздел "Программирование, языки" / Оглавление документа
Дальше: Приложение 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



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру