使用流式套接字编程,实现时间同步服务器,该服务器能够接受客户端的查询请求,获取本地时间,并将结果发送回客户端,同时开发与服务器通信的客户端,以验证双方交互的功能。这个可以实现网络中需要时间信号的设备如计算机、控制器等与标准时间源自动、定期的同步本机标准时间。
下面分别是服务器和客户端的源码:
服务器:
// DayTimeServer.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <time.h>
#include "Winsock2.h"
#include "stdio.h"
#define MAXLINE 4096 //接收缓冲区长度
#define LISTENQ 1024 //监听队列长度
#define SERVER_PORT 13 //时间获取服务器端口号
int main(int argc, char* argv[])
{
SOCKET ListenSocket = INVALID_SOCKET, ClientSocket = INVALID_SOCKET;
int iResult;
struct sockaddr_in servaddr;
char buff[MAXLINE];
time_t ticks;
int iSendResult;
//初始化Windows Sockets DLL,协商版本号
WORD wVersionRequested;
WSADATA wsaData;
// 使用 MAKEWORD(lowbyte, highbyte) 宏,在Windef.h 中声明
wVersionRequested = MAKEWORD(2, 2);
iResult = WSAStartup(wVersionRequested, &wsaData);
if (iResult != 0) {
//告知用户无法找到合适可用的Winsock DLL
printf("WSAStartup 函数调用错误,错误号: %d\n", WSAGetLastError());
return -1;
}
// 确认WinSock Dll支持版本2.2
// 注意,如果DLL支持的版本比2.2更高,根据用户调用前的需求,仍然返回2.2版本号,存储于wsaData.wVersion
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
// 告知用户无法找到可用的WinSock DLL.
printf("无法找到可用的Winsock.dll版本\n");
WSACleanup();
return -1;
}
else
printf("Winsock 2.2 dll初始化成功\n");
//创建流式套接字
if((ListenSocket = socket(AF_INET, SOCK_STREAM, 0))<0){
printf("socket 函数调用错误,错误号: %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERVER_PORT); /* daytime server */
//绑定服务器地址
iResult = bind( ListenSocket, (struct sockaddr *) & servaddr, sizeof (servaddr));
if (iResult == SOCKET_ERROR) {
printf("bind 函数调用错误,错误号: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return -1;
}
//设置服务器为监听状态,监听队列长度为LISTENQ
iResult = listen(ListenSocket, LISTENQ);
if (iResult == SOCKET_ERROR){
printf("listen 函数调用错误,错误号: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return -1;
}
for ( ; ; )
{
// 接受客户端连接请求,返回连接套接字ClientSocket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET){
printf("accept 函数调用错误,错误号: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return -1;
}
//获取当前时间
ticks = time(NULL);
memset(buff,0,sizeof(buff));
sprintf(buff, "%.24s\r\n", ctime(&ticks));
printf("获取当前系统时间: %s\n",buff );
//发送时间
iSendResult = send( ClientSocket, buff, strlen(buff), 0 );
if (iSendResult == SOCKET_ERROR) {
printf("send 函数调用错误,错误号: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return -1;
}
printf("向客户端发送时间成功\n");
// 停止连接,不再发送数据
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown 函数调用错误,错误号: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return -1;
}
// 关闭套接字
closesocket(ClientSocket);
printf("主动关闭连接\n");
}
closesocket(ListenSocket);
WSACleanup();
return 0;
}
客户端:
// DayTime.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "Winsock2.h"
#include "stdio.h"
#define MAXLINE 4096 //接收缓冲区长度
#define SERVER_PORT 13 //时间获取服务器端口号
int main(int argc, char* argv[])
{
SOCKET ConnectSocket = INVALID_SOCKET;
int iResult;
char recvline[MAXLINE + 1];
struct sockaddr_in servaddr;
if (argc != 2){
printf("usage: DayTime <IPaddress>");
return 0;
}
//初始化Windows Sockets DLL,协商版本号
WORD wVersionRequested;
WSADATA wsaData;
// 使用 MAKEWORD(lowbyte, highbyte) 宏,在Windef.h 中声明
wVersionRequested = MAKEWORD(2, 2);
iResult = WSAStartup(wVersionRequested, &wsaData);
if (iResult != 0) {
//告知用户无法找到合适可用的Winsock DLL
printf("WSAStartup 函数调用错误,错误号: %d\n", WSAGetLastError());
return -1;
}
// 确认WinSock Dll支持版本2.2
// 注意,如果DLL支持的版本比2.2更高,根据用户调用前的需求,仍然返回2.2版本号,存储于wsaData.wVersion
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
// 告知用户无法找到可用的WinSock DLL.
printf("无法找到可用的Winsock.dll版本\n");
WSACleanup();
return -1;
}
else
printf("Winsock 2.2 dll初始化成功\n");
//创建流式套接字
if((ConnectSocket = socket(AF_INET, SOCK_STREAM, 0))<0){
printf("socket 函数调用错误,错误号: %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
//服务器地址赋值
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERVER_PORT);
servaddr.sin_addr.s_addr=inet_addr(argv[1]);
//请求向服务器建立连接
iResult = connect( ConnectSocket, (LPSOCKADDR)&servaddr, sizeof(servaddr));
if (iResult == SOCKET_ERROR){
printf("connect 函数调用错误,错误号: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return -1;
}
// 持续接收数据,直到服务器方关闭连接
memset(&recvline, 0, sizeof(recvline));
printf("当前时间是:");
do {
Sleep(5000);
iResult = recv(ConnectSocket, recvline, MAXLINE, 0);
if (iResult > 0)
printf("%s", recvline);
else{
if (iResult == 0)
printf("对方连接关闭,退出\n");
else
printf("recv 函数调用错误,错误号: %d\n", WSAGetLastError());
}
memset(&recvline, 0, sizeof(recvline));
} while (iResult > 0);
closesocket(ConnectSocket);
WSACleanup();
return 0;
}