Windows下丢包率测试源码

来源:互联网 发布:中卫云计算2018,130 编辑:程序博客网 时间:2024/06/13 13:51

PacketLossTestClient:

PacketLossTestClient.cpp:
// PacketLossTestClient.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "SocketFrame.h"int udp_client_fun_packetloss(int times, SOCKET s);#define ECHOPORT "7210"int main(int argc, char* argv[]){CSocketFrame frame;int iResult;SOCKET ClientSocket;sockaddr_in servaddr;int times;//输入参数合法性检查if (argc != 3){printf("usage: PacketLossTestClient <IPaddress> <times>");return -1;}//Windows Sockets Dll初始化frame.start_up();//创建客户端的数据报套接字,并与服务器建立连接ClientSocket = frame.udp_client( ( char *)argv[1], ECHOPORT, true );if ( ClientSocket == -1 )return -1;    printf("客户端启动成功。\n");//开始回射请求的发送与接收//指明服务器的地址peer为用户输入的IP和端口号if (frame.set_address( ( char *)argv[1], ECHOPORT, &servaddr, "udp" ) !=0 )return 0;  times = atoi(argv[2]);iResult = udp_client_fun_packetloss(times, ClientSocket );    if(iResult == -1)    printf("当前测试出错!\n");frame.quit( ClientSocket );    return iResult; }/********************************************************函数名:udp_client_fun_packetloss输入参数:int times:发送次数          SOCKET s:客户端的数据报套接字输出参数:0:成功,-1:失败功能:丢包率测试客户端的具体功能函数*********************************************************/int udp_client_fun_packetloss(int times, SOCKET s){int iResult, i =0;    char sendline[MAXLINE];int recvtimes =0;memset(sendline,1,MAXLINE);//根据用户输入的发送次数循环发送相同的数据报printf("\r\n客户端发送%d次数据\r\n", times);while( i<times ){iResult = send(s,sendline,strlen(sendline),0 );if(iResult == SOCKET_ERROR){printf("send 函数调用错误,错误号: %ld\n", WSAGetLastError());return -1;}i++;}return iResult;}

SocketFrame.cpp:

#include "StdAfx.h"#include "SocketFrame.h"#include "ws2tcpip.h"#include "mstcpip.h"CSocketFrame::CSocketFrame(void){}CSocketFrame::~CSocketFrame(void){}/********************************************************函数名:set_address输入参数:char * hname:主机名 or 点分十进制表示的IP地址          char * sname:端口号  struct sockaddr_in * sap:以sockaddr_in结构存储的地址(输出参数)          char * protocol:字符串形式描述的协议类型,如"tcp"输出参数:0表示成功,-1表示失败。功能:根据给定的主机名或点分十进制表示的IP地址获得以sockaddr_in结构存储的地址*********************************************************/int CSocketFrame::set_address(char * hname, char * sname, struct sockaddr_in * sap, char * protocol){struct servent *sp;struct hostent *hp;char *endptr;unsigned short port;unsigned long ulAddr = INADDR_NONE;    //对地址结构socketaddr_in初始化为0,并设置地址族为AF_INETmemset( sap,0, sizeof( *sap ) );sap->sin_family = AF_INET;if ( hname != NULL ){//如果hname不为空,假定给出的hname为点分十进制表示的数字地址,转换地址为sockaddr_in类型ulAddr = inet_addr(hname);if ( ulAddr == INADDR_NONE || ulAddr == INADDR_ANY) {//printf("inet_addr 函数调用错误,错误号: %d\n", WSAGetLastError());//调用错误,表明给出的是主机名,调用gethostbyname获得主机地址hp = gethostbyname( hname );if ( hp == NULL ) {printf("未知的主机名,错误号: %d\n", WSAGetLastError());return -1;}sap->sin_addr = *( struct in_addr * )hp->h_addr;        }      elsesap->sin_addr.S_un.S_addr=ulAddr;}else//如果调用者没有指定一个主机名或地址,则设置地址为通配地址INADDR_ANYsap->sin_addr.s_addr = htonl( INADDR_ANY );//尝试转换sname为一个整数port = (unsigned short )strtol( sname, &endptr, 0 );if ( *endptr == '\0' ){//如果成功则转换为网络字节顺序sap->sin_port = htons( port );}else{//如果失败,则假定是一个服务名称,通过调用getservbyname获得端口号sp = getservbyname( sname, protocol );if ( sp == NULL ) {printf("未知的服务,错误号: %d\n", WSAGetLastError());return -1;}sap->sin_port = sp->s_port;}return 0;}/********************************************************函数名:start_up输入参数:无输出参数:0:成功,-1:失败功能:初始化Windows Sockets DLL,协商版本号*********************************************************/int CSocketFrame::start_up(void){WORD wVersionRequested;    WSADATA wsaData;    int iResult;    // 使用 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;    }return 0;}/********************************************************函数名:clean_up输入参数:无输出参数:0:成功,-1:失败功能:终止Windows Sockets DLL的使用,释放资源 *********************************************************/int CSocketFrame::clean_up(void){int iResult;iResult = WSACleanup();    if (iResult == SOCKET_ERROR) {        // WSACleanup调用失败                          printf("WSACleanup 函数调用错误,错误号: %d\n",  WSAGetLastError());        return -1;    }return 0;}/********************************************************函数名:quit输入参数:SOCKET s:服务器的连接套接字输出参数:0:成功,-1:失败功能:关闭套接字,释放dll*********************************************************/int CSocketFrame::quit(SOCKET s){    int iResult=0;    iResult = closesocket(s);    if (iResult == SOCKET_ERROR){        printf("closesocket 函数调用错误,错误号:%d\n", WSAGetLastError());        return -1;    }    iResult = clean_up();    return iResult;}/********************************************************函数名:tcp_server输入参数:char * hname:服务器主机名 or 点分十进制表示的IP地址          char * sname:服务端口号输出参数:创建服务器端流式套接字并配置,-1:表示失败功能:创建流式套接字,根据用户输入的地址和端口号,绑定套接字的服务地址      将其转换为监听状态*********************************************************/SOCKET CSocketFrame::tcp_server( char *hname, char *sname ){sockaddr_in local;SOCKET ListenSocket;const int on = 1;int iResult = 0;    //为服务器的本地地址local设置用户输入的IP和端口号if (set_address( hname, sname, &local, "tcp" ) !=0 )return -1;//创建套接字ListenSocket = socket( AF_INET, SOCK_STREAM, 0 );if (ListenSocket == INVALID_SOCKET) {        printf("socket 函数调用错误,错误号: %ld\n", WSAGetLastError());        clean_up();        return -1;    }//设置服务器地址可重用选项iResult = setsockopt( ListenSocket, SOL_SOCKET, SO_REUSEADDR, ( char * )&on, sizeof( on ));if ( iResult == SOCKET_ERROR){printf("setsockopt函数调用错误,错误号: %d\n", WSAGetLastError());        quit(ListenSocket);        return -1;    }    //绑定服务器地址iResult = bind( ListenSocket, (struct sockaddr *) & local, sizeof (local));    if (iResult == SOCKET_ERROR) {        printf("bind 函数调用错误,错误号: %d\n", WSAGetLastError());        quit(ListenSocket);        return -1;    }//设置服务器为监听状态,监听队列长度为NLISTEN    iResult = listen(ListenSocket, SOMAXCONN);if (iResult == SOCKET_ERROR){printf("listen 函数调用错误,错误号: %d\n", WSAGetLastError());quit(ListenSocket);return -1;    }return ListenSocket;}/********************************************************函数名:tcp_client输入参数:char * hname:服务器主机名 or 点分十进制表示的IP地址          char * sname:服务端口号输出参数:创建客户端流式套接字,-1:表示失败功能:创建流式套接字,根据用户输入的地址和端口号,向服务地址      请求建立连接*********************************************************/SOCKET CSocketFrame::tcp_client( char *hname, char *sname ){struct sockaddr_in peer;SOCKET ClientSocket;int iResult = 0;//指明服务器的地址peer为用户输入的IP和端口号if (set_address( hname, sname, &peer, "tcp" ) !=0 )return -1;//创建套接字ClientSocket = socket( AF_INET, SOCK_STREAM, 0 );if (ClientSocket == INVALID_SOCKET) {        printf("socket 函数调用错误,错误号: %ld\n", WSAGetLastError());        clean_up();        return -1;    }    //请求向服务器建立连接iResult =connect( ClientSocket, ( struct sockaddr * )&peer, sizeof( peer ) );if (iResult == SOCKET_ERROR){printf("connect 函数调用错误,错误号: %d\n", WSAGetLastError());quit(ClientSocket);return -1;    }return ClientSocket;}/********************************************************函数名:recvn输入参数:SOCKET s:服务器的连接套接字          char * recvbuf:存放接收到数据的缓冲区   int fixedlen:固定的预接收数据长度输出参数:>0:实际接收到的字节数,-1:失败功能:在流式套接字中接收固定长度的数据********************************************************/int CSocketFrame::recvn(SOCKET s, char * recvbuf, unsigned int fixedlen){int iResult;//存储单次recv操作的返回值int cnt;//用于统计相对于固定长度,剩余多少字节尚未接收cnt = fixedlen;while ( cnt > 0 ){        iResult = recv(s, recvbuf, cnt, 0);        if ( iResult < 0 ){//数据接收出现错误,返回失败printf("接收发生错误: %d\n", WSAGetLastError());    return -1;}    if ( iResult == 0 ){//对方关闭连接,返回已接收到的小于fixedlen的字节数        printf("连接关闭\n");return fixedlen - cnt;}    //printf("接收到的字节数: %d\n", iResult);//接收缓存指针向后移动recvbuf +=iResult;//更新cnt值cnt -=iResult;         }return fixedlen;}/********************************************************函数名:recvvl输入参数:SOCKET s:服务器的连接套接字          char * recvbuf:存放接收到数据的缓冲区   int recvbuflen:接收缓冲区长度输出参数:>0:实际接收到的字节数,-1:失败,0:连接关闭功能:在流式套接字中接收可变长度的数据********************************************************/int CSocketFrame::recvvl(SOCKET s, char * recvbuf, unsigned int recvbuflen){int iResult;//存储单次recv操作的返回值unsigned int reclen; //用于存储报文头部存储的长度信息//获取接收报文长度信息    iResult = recvn(s, ( char * )&reclen, sizeof( unsigned int ));if ( iResult !=sizeof ( unsigned int )){//如果长度字段在接收时没有返回一个整型数据就返回0(连接关闭)或-1(发生错误)if ( iResult == -1 ){         printf("接收发生错误: %d\n", WSAGetLastError());     return -1;}else{ printf("连接关闭\n");             return 0;}}//转换网络字节顺序到主机字节顺序reclen = ntohl( reclen );if ( reclen > recvbuflen ){//如果recvbuf没有足够的空间存储变长消息,则接收该消息并丢弃,返回错误while ( reclen > 0){iResult = recvn( s, recvbuf, recvbuflen );if ( iResult != recvbuflen ){//如果变长消息在接收时没有返回足够的数据就返回0(连接关闭)或-1(发生错误)if ( iResult == -1 ){ printf("接收发生错误: %d\n", WSAGetLastError()); return -1;}else{ printf("连接关闭\n"); return 0;}}reclen -= recvbuflen;//处理最后一段数据长度if ( reclen < recvbuflen )recvbuflen = reclen;}printf("可变长度的消息超出预分配的接收缓存\r\n");return -1;}//接收可变长消息iResult = recvn( s, recvbuf, reclen );if ( iResult != reclen ){        //如果消息在接收时没有返回足够的数据就返回0(连接关闭)或-1(发生错误)if ( iResult == -1 ){         printf("接收发生错误: %d\n", WSAGetLastError());     return -1;}else{ printf("连接关闭\n");             return 0;}}return iResult;}/********************************************************函数名:udp_server输入参数:char * hname:服务器主机名 or 点分十进制表示的IP地址          char * sname:服务端口号输出参数:创建服务器端流式套接字并配置,-1:表示失败功能:创建流式套接字,根据用户输入的地址和端口号,绑定套接字的服务地址      将其转换为监听状态*********************************************************/SOCKET CSocketFrame::udp_server( char *hname, char *sname ){sockaddr_in local;SOCKET ServerSocket;const int on = 1;int iResult = 0;    //为服务器的本地地址local设置用户输入的IP和端口号if (set_address( hname, sname, &local, "udp" ) !=0 )return -1;//创建套接字ServerSocket = socket( AF_INET, SOCK_DGRAM, 0 );if (ServerSocket == INVALID_SOCKET) {        printf("socket 函数调用错误,错误号: %ld\n", WSAGetLastError());        clean_up();        return -1;    }//设置服务器地址可重用选项iResult = setsockopt( ServerSocket, SOL_SOCKET, SO_REUSEADDR, ( char * )&on, sizeof( on ));if ( iResult == SOCKET_ERROR){printf("setsockopt函数调用错误,错误号: %d\n", WSAGetLastError());        quit(ServerSocket);        return -1;    }    //绑定服务器地址iResult = bind( ServerSocket, (struct sockaddr *) & local, sizeof (local));    if (iResult == SOCKET_ERROR) {        printf("bind 函数调用错误,错误号: %d\n", WSAGetLastError());        quit(ServerSocket);        return -1;    }return ServerSocket;}/********************************************************函数名:udp_client输入参数:char * hname:服务器主机名 or 点分十进制表示的IP地址          char * sname:服务端口号  BOOL flag:工作模式标识,true表示连接模式,false表示非连接模式输出参数:创建客户端流式套接字,-1:表示失败功能:创建数据报套接字,根据用户输入的地址和端口号*********************************************************/SOCKET CSocketFrame::udp_client( char *hname, char *sname, BOOL flag){struct sockaddr_in peer;SOCKET ClientSocket;int iResult = -1;//指明服务器的地址peer为用户输入的IP和端口号if (set_address( hname, sname, &peer, "udp" ) ==1 )return -1;//创建套接字ClientSocket = socket( AF_INET, SOCK_DGRAM, 0 );if (ClientSocket == INVALID_SOCKET) {        printf("socket 函数调用错误,错误号: %ld\n", WSAGetLastError());        clean_up();        return -1;    }if( flag == TRUE){//连接模式//请求向服务器建立连接    iResult =connect( ClientSocket, ( struct sockaddr * )&peer, sizeof( peer ) );    if (iResult == SOCKET_ERROR){    printf("connect 函数调用错误,错误号: %d\n", WSAGetLastError());    quit(ClientSocket);    return -1;}    }return ClientSocket;}/********************************************************函数名:check_sum输入参数:  USHORT *pchBuffer:待计算校验和的缓冲区  int iSize:待计算校验和缓冲区长度输出参数:校验和功能:计算校验和*********************************************************/USHORT CSocketFrame::check_sum(USHORT *pchBuffer, int iSize){    unsigned long ulCksum=0;    while (iSize > 1)     {        ulCksum += *pchBuffer++;        iSize -= sizeof(USHORT);    }    if (iSize)     {        ulCksum += *(UCHAR*)pchBuffer;    }    ulCksum = (ulCksum >> 16) + (ulCksum & 0xffff);    ulCksum += (ulCksum >>16);    return (USHORT)(~ulCksum);}/********************************************************函数名:raw_socket输入参数:  BOOL bSendflag:首部控制选项  BOOL bRecvflag:接收控制选项  int iProtocol:协议设置,具体内容参考MSDN对协议的定义,如#define IPPROTO_IP 0  sockaddr_in *pLocalIP:指向本地IP地址的指针,返回参数,如果存在多个接口地址,获取用户选择的本地地址输出参数:创建客户端流式套接字,-1:表示失败功能:创建数据报套接字,根据用户输入的地址和端口号*********************************************************/SOCKET CSocketFrame::raw_socket( BOOL bSendflag, BOOL bRecvflag, int iProtocol, sockaddr_in *pLocalIP){SOCKET RawSocket;int iResult = 0;struct hostent *local;    char HostName[DEFAULT_NAMELEN];struct in_addr addr;    int in=0,i=0;    DWORD dwBufferLen[10]; DWORD Optval= 1 ;    DWORD dwBytesReturned = 0 ;//创建套接字RawSocket = socket( AF_INET, SOCK_RAW, iProtocol );if (RawSocket == INVALID_SOCKET) {        printf("socket 函数调用错误,错误号: %ld\n", WSAGetLastError());        clean_up();        return -1;    }if( bSendflag == TRUE){//设置IP_HDRINCL表示要构造IP头,需#include "ws2tcpip.h"    iResult = setsockopt(RawSocket,IPPROTO_IP,IP_HDRINCL,(char*)&bSendflag,sizeof(bSendflag));if (iResult == SOCKET_ERROR){    printf("setsockopt 函数调用错误,错误号: %d\n", WSAGetLastError());    quit(RawSocket);    return -1;}    }if( bRecvflag == TRUE){//设置I/O控制选项,接收全部IP包//获取本机名称    memset( HostName, 0, DEFAULT_NAMELEN);    iResult = gethostname( HostName, sizeof(HostName));    if ( iResult ==SOCKET_ERROR) {      printf("gethostname 函数调用错误,错误号: %ld\n", WSAGetLastError());      quit(RawSocket);      return -1;    }    //获取本机可用IP    local = gethostbyname( HostName);    printf ("\n本机可用的IP地址为:\n");    if( local ==NULL)    {        printf("gethostbyname 函数调用错误,错误号: %ld\n", WSAGetLastError());        quit(RawSocket);        return -1;    }    while (local->h_addr_list[i] != 0) {        addr.s_addr = *(u_long *) local->h_addr_list[i++];        printf("\tIP Address #%d: %s\n", i, inet_ntoa(addr));    }       printf ("\n请选择捕获数据待使用的接口号:");    scanf_s( "%d", &in);        memset( pLocalIP, 0, sizeof(sockaddr_in));    memcpy( &pLocalIP->sin_addr.S_un.S_addr, local->h_addr_list[in-1], sizeof(pLocalIP->sin_addr.S_un.S_addr));    pLocalIP->sin_family = AF_INET;    pLocalIP->sin_port = 0;    //绑定本地地址    iResult = bind( RawSocket, (struct sockaddr *) pLocalIP, sizeof(sockaddr_in));    if( iResult == SOCKET_ERROR){        printf("bind 函数调用错误,错误号: %ld\n", WSAGetLastError());        quit(RawSocket);return -1;    }    printf(" \n成功绑定套接字和#%d号接口地址", in);    //设置套接字接收命令    iResult = WSAIoctl(RawSocket, SIO_RCVALL , &Optval, sizeof(Optval),  &dwBufferLen, sizeof(dwBufferLen), &dwBytesReturned , NULL , NULL );    if ( iResult == SOCKET_ERROR ){        printf("WSAIoctl 函数调用错误,错误号: %ld\n", WSAGetLastError());        quit(RawSocket);return -1;    }}return RawSocket;}

SocketFrame.h:
#pragma once#include "winsock2.h"#include "stdio.h"#pragma comment(lib,"ws2_32.lib")//定义网络框架程序中所需的宏#define TRUE1#define FALSE0#defineMAXLINE    200    // max text line length #defineDEFAULT_NAMELEN 100 //默认的名字长度//首部结构定义typedef struct tagIPHDR{UCHAR hdr_len :4;  // length of the header    UCHAR version :4;  // version of IPUCHARTOS;   // Type of serviceUSHORTTotLen;   // Total lengthUSHORTID;   // IdentificationUSHORTFlagOff;   // Flags and fragment offsetUCHARTTL;   // Time-to-liveUCHARProtocol;  // ProtocolUSHORTChecksum;  // ChecksumULONG IPSrc;   // Internet address, sourceULONG IPDst;   // Internet address, destination} IPHDR, *PIPHDR;typedef struct tagUDPHDR//UDP头定义{USHORT src_portno; USHORT dst_portno; USHORT udp_length; USHORT udp_checksum; } UDPHDR,*PUDPHDR;typedef struct tagTCPHDR//TCP首部定义{USHORT  sport;            //Source port     USHORT  dport;            //Destination port     ULONG   seq;              //Sequence number     ULONG   ack;              //Ack number     BYTE    hlen;             // TCP header len (num of bytes << 2)     BYTE    flags;            // Option flags     USHORT  window;           // Flow control credit (num of bytes)     USHORT  check;            // Checksum     USHORT  urgent;           // Urgent data pointer } TCPHDR,*PTCPHDR;//TCP标志字段定义#define TFIN        0x01    // Option flags: no more data #define TSYN        0x02    // sync sequence nums #define TRST        0x04    // reset connection #define TPUSH       0x08    // push buffered data #define TACK        0x10    // acknowledgement #define TURGE       0x20    // urgent typedef struct tagFHDR//UDP伪首部定义{ULONG IPSrc;ULONG IPDst;UCHAR zero;UCHAR protocol;USHORT udp_length;} FHDR,*PFHDR;//ICMP数据报头typedef struct tagICMPHDR{    UCHAR type;  //8位类型    UCHAR code;  //8位代码    USHORT cksum;  //16位校验和    USHORT id;   //16位标识符    USHORT seq;  //16位序列号} ICMPHDR,*PICMPHDR;#pragma pack()//ICMP类型字段const BYTE ICMP_ECHO_REQUEST = 8; //请求回显const BYTE ICMP_ECHO_REPLY  = 0; //回显应答const BYTE ICMP_TIMEOUT   = 11; //传输超时const DWORD DEF_ICMP_TIMEOUT = 3000; //默认超时时间,单位msconst int DEF_ICMP_DATA_SIZE = 32; //默认ICMP数据部分长度const int MAX_ICMP_PACKET_SIZE = 1024; //最大ICMP数据报的大小const int DEF_MAX_HOP = 30;    //最大跳站数class CSocketFrame{public:CSocketFrame(void);~CSocketFrame(void);int set_address(char * hname, char * sname, struct sockaddr_in * sap, char * protocol);int start_up(void);int clean_up(void);int quit(SOCKET s);USHORT check_sum(USHORT *pchBuffer, int iSize);SOCKET tcp_server( char *hname, char *sname );SOCKET udp_server( char *hname, char *sname );int recvn(SOCKET s, char * recvbuf, unsigned int fixedlen);int recvvl(SOCKET s, char * recvbuf, unsigned int recvbuflen);SOCKET tcp_client( char *hname, char *sname );SOCKET udp_client( char *hname, char *sname, BOOL flag);    SOCKET raw_socket( BOOL bSendflag, BOOL bRecvflag, int iProtocol, sockaddr_in *pLocalIP);};

PacketLossTestServer:

// PacketLossTestServer.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "SocketFrame.h"#include "winsock2.h"#define ECHOPORT "7210"#define TIMEOVER 1000int udp_server_fun_packetloss( SOCKET s );int main(int argc, char* argv[]){CSocketFrame frame;int iResult = 0;SOCKET ServerSocket;//输入参数合法性检查if (argc != 2){printf("usage: PacketLossTestServer <recvbuflen>");return -1;}//Windows Sockets Dll初始化frame.start_up();//创建服务器端的数据报套接字并绑定端点地址ServerSocket = frame.udp_server( NULL, ECHOPORT );if ( ServerSocket == -1 )return -1;int rcvbuf_len; int len = sizeof(rcvbuf_len); if(getsockopt( ServerSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbuf_len, &len ) < 0)  {    printf("getsockopt error\n" );    return -1; } printf("系统接收缓存默认大小: %d\n", rcvbuf_len );//获得用户输入的系统缓存大小并设置rcvbuf_len = atoi(argv[1]); if(setsockopt( ServerSocket, SOL_SOCKET, SO_RCVBUF, (const char *)&rcvbuf_len, len ) < 0 ){    printf("setsockopt error\n" );    return -1;}printf("系统接收缓存被设置为: %d\n", rcvbuf_len );//设置套接字的接收超时时间    int nTimeOver=TIMEOVER;//超时时限为1000ms if(setsockopt(ServerSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&nTimeOver,sizeof(nTimeOver)) < 0 )    {    printf("setsockopt error\n" );    return -1;}printf("系统接收超时时间被设置为: %d毫秒\n", nTimeOver );    printf("服务器准备好丢包率测试服务。。。\n");for ( ; ; ) {//接收并统计数据报文个数iResult = udp_server_fun_packetloss( ServerSocket );//如果出错,继续接收其它客户端的测试请求if(iResult == -1)printf("当前测试出错!\n");}frame.quit( ServerSocket );    return 0;}/********************************************************函数名:udp_server_packetloss输入参数:SOCKET s:服务器的数据报套接字输出参数:0:成功,-1:失败功能:丢包率测试服务器的具体功能函数********************************************************/int udp_server_fun_packetloss( SOCKET s ){int iResult = 0;int count = 0;struct sockaddr_incliaddr;int addrlen =sizeof( sockaddr_in );char    recvline[MAXLINE];do {memset( recvline, 0, MAXLINE );//接收数据     iResult = recvfrom( s, recvline, MAXLINE, 0, (SOCKADDR *)&cliaddr, &addrlen);if (iResult > 0){count++;}else{ int err = WSAGetLastError();//当出现非接收超时的错误时打印错误号if ( err != 10060){    printf("recvfrom 函数调用错误,错误号: %d\n",err);iResult = -1;}else{iResult = 0; break;}            } } while (iResult > 0);if( count>0)       printf("服务器端总共收到%d个数据报\n", count);return iResult;}
在相同的目录下也有SocketFrame.cpp和SocketFrame.h文件

0 0
原创粉丝点击