WinSock网络编程学习笔记(九):基于UDP实现DayTime协议

在一个局域网中,许多系统都要求每台计算机能够保持时间的一致性,如WIN2000系统提供了与主域服务器时间同步的功能,即计算机登录到主域服务器,计算机系统的时间自动与主域服务器时间一致。那么又是如何使得主域服务器的时间同步世界标准时间的呢?
如果能够使用GPS卫星时钟获得毫秒级别的标准时间,那会是很棒的一件事,前提了你付了钱!另一个不错的选择是,我们可以连接到Internet,利用Internet上的标准时间服务器获得标准时间,虽然只有秒级精度,不过对我们来说足够了,因为我们几乎不会用电脑时间来做秒表的...
实际上,在Innternet上有三个不同的时间服务,每一个都由RFC(Request for Comment)定义为Internet时间标准。这三个标准分别是:RFC-867、RFC-868、RFC-1305。今天我学习的就是:RFC-867 DayTime协议(RFC867 DayTime Protocol)。
Daytime是互联网的一个标准协议,该协议不指定固定的传输格式,只要按照ASCII标准发送数据即可。它也是一个非常有用的测量和调试工具--测试电脑网络连通性。不过这个方法当前似乎有点非主流了(对吗?),因为现在人们更多的是使用ping或者traceroute。
它即可以使用TCP,也可以使用UDP,知名端口号是13。
下面是DayTime客户端和服务器程序(示例):
1.客户端:
#include
#include

#pragma comment(lib,"ws2_32.lib")	//winsock 使用的库函数

#define DAY_TIME_DEF_PORT 13		//默认端口	
#define DAY_TIME_BUF_SIZE 64		//缓冲区大小
#define DAY_TIME_DEF_COUNT 2		//发送的次数

int main(int argc , char **argv)
{
	WSADATA wsaData;
	SOCKET time_soc = 0;
	struct  sockaddr_in  peer_addr,serv_addr;
	int timeout = 2000;				//接收超时,2s
	int i,
		result,
		send_len,
		addr_len = sizeof(serv_addr);
	char *dest = "127.0.0.1",
		 *send_data = "Hello,DayTime!";
	char recv_buf[ DAY_TIME_BUF_SIZE ];

	if(argc == 2)
		dest = argv[1];
	WSAStartup(WINSOCK_VERSION,&wsaData);			//初始化Winsock资源
	send_len = strlen(send_data);
	//填写服务器地址
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(DAY_TIME_DEF_PORT);
	serv_addr.sin_addr.s_addr = inet_addr(dest);	//当然是转网络字节序
	//错误判断,都是程序化的步骤(套路)...
	if(serv_addr.sin_addr.s_addr == INADDR_NONE)
	{
		printf("[DayTime]invaild address\r\n");
		return -1;
	}
	//创建DayTime使用的Socket,注意是 “SOCK_DGRAM”类型,协议为:UDP:无连接、不可靠的传输服务
	time_soc = socket(AF_INET,SOCK_DGRAM,0);
	
	result = setsockopt(time_soc,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(timeout));
	/*设置接收数据的超时值,这样做的目的是,一旦数据丢失,客户端不会收到服务器的数据。
	  客户端使用的是阻塞套接口,程序永远阻塞在 recvfrom函数,无法进行其他处理。
	  设置超时时间后,recvfrom函数会返回SOCKET_ERROR,程序会继续执行,重发数据。
	*/
	/*
	UDP是不可靠的,下面使用循环,设置的是消息发送两次,
	*/
	for(i = 0;i= 0)
		{
			recv_buf[result] = 0;
			printf( " [Daytime]recv: \"%s\" ,from : %s\r\n" , recv_buf , inet_ntoa(peer_addr.sin_addr) );
		}
	}
	closesocket(time_soc);
	WSACleanup();
	return 0;
}


2.服务器端:
#include
#include
#include

#pragma comment(lib,"ws2_32.lib")

#define DAY_TIME_DEF_PORT 13
#define DAY_TIME_BUF_SIZE 64
#define DAY_TIME_DEF_COUNT 2

int main(int argc , char **argv)
{
	WSADATA wsaData;
	SOCKET serv_sock = 0;
	struct  sockaddr_in  serv_addr,		//服务器端句柄
						 clnt_addr;		//客户端句柄
	unsigned short port = DAY_TIME_DEF_PORT;
	int result,
		addr_len = sizeof(serv_addr);
	char *time_str,
		 recv_buf[ DAY_TIME_BUF_SIZE ];
	time_t now_time;
	WSAStartup(WINSOCK_VERSION,&wsaData);	//初始化
	if(argc == 2)
		port = atoi(argv[1]);
	serv_sock = socket(AF_INET,SOCK_DGRAM,0);
	//
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(port);
	serv_addr.sin_addr.s_addr =	INADDR_ANY;
	//调用bind为套接口绑定本地地址

	result = bind(serv_sock,(struct sockaddr *)&serv_addr,addr_len);
	if( result == SOCKET_ERROR)
	{
		printf("[Daytime]bind error : %d",WSAGetLastError());
		closesocket(serv_sock);
		return -1;
	}
	printf("[Daytime] the server is running...\n");
	while(1)
	{
		result = recvfrom( serv_sock , recv_buf , DAY_TIME_BUF_SIZE , 0 , (struct sockaddr*)&clnt_addr , &addr_len);
		if(result >= 0)	//表示收到对方数据
		{
			recv_buf[result] = 0;
			printf( " [Daytime]recv: \"%s\" ,from : %s\r\n" , recv_buf , inet_ntoa(clnt_addr.sin_addr) );
			now_time = time(0);			//得到当前时间
			time_str = ctime(&now_time);//转字符串
			//向客户端发送当前的日期和时间字符串
		    sendto( serv_sock,time_str,strlen(time_str),0,(struct sockaddr*)&clnt_addr , addr_len);
		}
	}
	closesocket(serv_sock);
	WSACleanup();
	return 0;


}

运行结果:
WinSock网络编程学习笔记(九):基于UDP实现DayTime协议_第1张图片

你可能感兴趣的:(Socket)