客户端程序如下:
//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(); }