客户端程序如下:
//Client.cpp
#include <stdio.h>
#include <winsock2.h>
#include <time.h>
#include <conio.h>
#pragma comment(lib,"ws2_32.lib")
int main(void)
{
WSADATA wsa;
/*struct WSAData
{
WORD wVersion;
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYSSTATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
};
WSADATA结构被用来保存AfxSocketInit函数返回的WindowsSockets初始化信息*/
WSAStartup(MAKEWORD(2,2),&wsa);
//WORD MAKEWORD(BYTE,BYTE ) 返回版本号,WSADATA 的前两个参数
//WSA(Windows Sockets Asynchronous,Windows异步套接字)的启动命令
SOCKET mySocket;
mySocket = socket(AF_INET,SOCK_DGRAM,0);
//SOCKET WSAAPI socket(IN int af,IN int type,IN int protocol);
//AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合
//流式Socket(SOCK_STREAM)是一种面向连接的Socket,针对于面向连接的TCP服务应用。
//数据报式Socket(SOCK_DGRAM)是一种无连接的Socket,对应于无连接的UDP服务应用
//参数3,常用协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC
//为0时,会自动选择第二个参数类型对应的默认协议
struct sockaddr_in addr;
/*structsockaddr_in
{
short sin_family;//*Addressfamily一般来说AF_INET(地址族)PF_INET(协议族)
unsigned short sin_port;/*Portnumber(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)
struct in_addr sin_addr;//*Internetaddress
unsigned char sin_zero[8];//*Samesizeasstructsockaddr没有实际意义,只是为了跟SOCKADDR结构在内存中对齐
};*/
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("172.16.70.80");
//将一个点分十进制的IP转换成一个长整数型数(u_long类型)
addr.sin_port = htons(8000);
//将一个无符号短整型的主机数值转换为网络字节顺序,即大尾顺序(big-endian)
int len = sizeof(addr);
while(1)
{
printf("请输入一段字符串用户测试延迟:");
char buff[1024] = "\0";
scanf("%s",buff);
LARGE_INTEGER t1,t2,feq;
/*struct union LARGE_INTEGER
{
DWORD LowPart;
LONG HighPart;
};
64位有符号整数*/
QueryPerformanceFrequency(&feq);//每秒跳动次数
//BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
//返回值:非零,硬件支持高精度计数器;零,硬件不支持,读取失败。
if(sendto(mySocket,buff,sizeof(buff),0,(struct sockaddr *)&addr,len) == SOCKET_ERROR)
{
printf("发送错误!!!");
}
//sendto()适用于发送未建立连接的UDP数据报 (参数为SOCK_DGRAM)
/*int PASCAL FAR sendto (
IN SOCKET s,
IN const char FAR * buf,
IN int len,
IN int flags,
IN const struct sockaddr FAR *to,
IN int tolen);*/
QueryPerformanceCounter(&t1);//测前跳动次数
//在定时前应该先调用QueryPerformanceFrequency()函数获得机器内部计时器的时钟频率。
//接着在需要严格计时的事件发生前和发生之后分别调用QueryPerformanceCounter(),
//利用两次获得的计数之差和时钟频率,就可以计算出事件经历的精确时间
if(recvfrom(mySocket,buff,sizeof(buff),0,(struct sockaddr*)&addr,&len) == SOCKET_ERROR)
{
printf("接受错误!!!");
}
//ssize_t recvfrom(int sockfd,void *buf,int len,unsigned int flags, struct sockaddr *from,socket_t *fromlen);
//ssize_t 相当于 int,socket_t 相当于int ,这里用这个名字为的是提高代码的自说明性。
//buf:接收数据缓冲区
//from:(可选)指针,指向装有源地址的缓冲区
//fromlen:(可选)指针,指向from缓冲区长度值。
QueryPerformanceCounter(&t2);//测后跳动次数
//t2.LowPart //low 8 bit
//t2.QuadPart //64 bit bunber
printf("从服务端返回:%s\n",buff);
printf("--->>时间延迟:%f秒\n",((double)t2.QuadPart-(double)t1.QuadPart)/((double)feq.QuadPart));
}
closesocket(mySocket);
WSACleanup();
return 0;
getch();
}
服务器程序如下:
//Server.cpp
#include <stdio.h>
#include <conio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
int main(void)
{
WSADATA wsa;
WSAStartup(MAKEWORD(2,2),&wsa);
//windows Sockets Asynchronous start up
struct sockaddr_in addr_server;
addr_server.sin_family = AF_INET;
addr_server.sin_port = htons(8000);
addr_server.sin_addr.s_addr = INADDR_ANY;
SOCKET serversocket = socket(AF_INET,SOCK_DGRAM,0);
bind(serversocket,(struct sockaddr*)&addr_server,sizeof(addr_server));
//int bind(int sockfd, struct sockaddr * my_addr, int addrlen);
//用来设置给参数sockfd 的socket 一个名称. 此名称由参数my_addr 指向一sockaddr 结构,
//对于不同的socket domain 定义了一个通用的数据结构
struct sockaddr_in addr_from;
int fromlen = sizeof(addr_from);
while(1)
{
char frombuff[1024] = "\0";
printf("等待客户端输入信息!");
if(recvfrom(serversocket,frombuff,sizeof(frombuff),0,(struct sockaddr*)&addr_from,&fromlen) == SOCKET_ERROR)
{
printf("服务端接受有错误!!");
}
printf("客户端输入的是:%s\n",frombuff);
//Sleep(5000);
if(sendto(serversocket,frombuff,sizeof(frombuff),0,(struct sockaddr*)&addr_from,fromlen) == SOCKET_ERROR)
{
printf("服务端发送错误!!");
}
}
closesocket(serversocket);
WSACleanup();
return 0;
getch();
}