//丢包率测试,服务器端
#define NETWORK2_2_COMM_H
#define NETWORK2_2_COMM_H
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <inaddr.h>
#include <string.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib")
#define MAXLINE 4096 // 接收缓冲区长度
#define SEVER_PORT 13131 //
using namespace std;
int SETBUFF = 128; // 设置缓冲区大小
int RECVTIMEOUT = 1; // 设置服务器收包超时时间(ms)
int sum;
/*套接字初始化*/
int StartUp()
{
WORD w_version = MAKEWORD(2, 2);
WSADATA wsa_data;
int res = WSAStartup(w_version, &wsa_data);
if (res != 0)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
return -1;
}//版本号错误
if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
WSACleanup();
return -1;
}
return 0; //成功返回0
}
/*释放资源*/
int cleanUp()
{
int res = WSACleanup();
if (res == SOCKET_ERROR)
{
printf("WSACleanup Error:%d",WSAGetLastError());
return -1;
}
return 0;
}
/*断开连接,释放资源*/
int closeConn(SOCKET sock_conn)
{
int res = closesocket(sock_conn); //关闭连接
if (res == SOCKET_ERROR)
{
printf("关闭连接失败%d\n",WSAGetLastError());
return -1;
}
res = cleanUp();
return res;
}
/*服务器初始化*/
SOCKET udpServerInit(int port)
{
int res = -1;
SOCKET sock_listen;
const int on = 1;
// 绑定地址、端口
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
// server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_addr.s_addr = (INADDR_ANY);
server_addr.sin_port = htons(port);
//创建监听套接字
sock_listen = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_listen == INVALID_SOCKET)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
cleanUp();
return -1;
}
//绑定服务器地址
res = bind(sock_listen, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (res == SOCKET_ERROR)
{
printf("绑定失败:%d\n",WSAGetLastError());
closeConn(sock_listen);
return -1;
}
return sock_listen;
}
/*服务器丢包率测试函数*/
int udpServerPacket(SOCKET sock_conn)
{
int sock_res = 0;
int count = 0;
sockaddr_in client_addr;
int addr_len = sizeof(sockaddr_in);
char recv_data[MAXLINE];
char buf[64];//先获取包的数量
int val;
int recvbuflen=65535,tmp,len=sizeof(int);
int timeout=0,tmptimeout;
val=getsockopt(sock_conn,SOL_SOCKET,SO_RCVBUF,(char*)&tmp,&len);//恢复缓冲区接收包数量
// printf("return %d\n",val);
val=getsockopt(sock_conn,SOL_SOCKET,SO_RCVTIMEO,(char*)&tmptimeout,&len);//恢复超时时间
// printf("return %d\n",val);
val=setsockopt(sock_conn,SOL_SOCKET,SO_RCVBUF,(char*)&recvbuflen,len);
// printf("return %d\n",val);
val=getsockopt(sock_conn,SOL_SOCKET,SO_RCVBUF,(char*)&recvbuflen,&len);//恢复缓冲区接收包数量
// printf("recvbuflen is :%d\n",recvbuflen);
val=setsockopt(sock_conn,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,len);
// printf("return %d\n",val);
val=getsockopt(sock_conn,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,&len);//恢复缓冲区接收包数量
// printf("return %d\n",val);
// printf("timeout is :%d\n",timeout);
ZeroMemory(buf,64);
val=recvfrom(sock_conn,buf,sizeof(buf),0,(sockaddr*)&client_addr,&addr_len);
// printf("recvfrom return %d %d\n",val,WSAGetLastError());
if(val>0){
// puts(buf);
// printf("val is:%d\n",val);
string s=buf;
sum=atoi(s.c_str());
printf("预计接收包数为:%d\n",sum);
}
val=setsockopt(sock_conn,SOL_SOCKET,SO_RCVBUF,(char*)&tmp,len);
val=setsockopt(sock_conn,SOL_SOCKET,SO_RCVTIMEO,(char*)&tmptimeout,len);
int i=sum;
do {
memset(recv_data, 0, MAXLINE);
sock_res = recvfrom(sock_conn, recv_data, MAXLINE, 0, (SOCKADDR *) &client_addr, &addr_len);
if (sock_res >= 0) {
count += 1;
}
else {
continue;
// int error = WSAGetLastError();
// // 10060 超时
// if (error == 10060) {
printf("recvfrom timeout error\n");
// } else {
// sock_res = 0;
// printf(" exit id: %d \n",error);
// break;
// }
}
} while (--i);
if (count > 0)
{
double result=((double)sum-(double)count)/(double)sum*100;
printf("共接收到的包的数量为:%-5d 丢包率:%.2lf%% \n",count,result);
}
return sock_res;
}
int main(int argc, char *argv[]) {
int sock_res;
SOCKET sock_listen;
if (StartUp() == -1) return -1; // 启动
sock_listen = udpServerInit(SEVER_PORT); //监听
if (sock_listen == -1) return -1;
puts("服务器启动成功");
//设置SO_RCVBUF选项,改变缓冲区大小
int recv_buff_len;
int len = sizeof(recv_buff_len);
if (getsockopt(sock_listen, SOL_SOCKET, SO_RCVBUF, (char *) &recv_buff_len, &len)<0)
{
puts("getsockopt error");
return -1;
}
printf("默认缓冲区大小:%d\n",recv_buff_len);
getsockopt(sock_listen, SOL_SOCKET, SO_RCVTIMEO, (char *) &recv_buff_len, &len);
printf("默认超时时间大小:%d\n",recv_buff_len);
//更改缓冲区大小
printf("输入设置的内核套接口缓冲区大小:");
scanf("%d",&SETBUFF);
recv_buff_len = SETBUFF;
if (setsockopt(sock_listen, SOL_SOCKET, SO_RCVBUF, (char *) &recv_buff_len, len)<0)
{
puts("setsockopt error");
return -1;
}
printf("更改后的缓冲区大小:%d\n",recv_buff_len);
//设置接收包的超时时间
printf("输入接受包的超时时间(ms):");
scanf("%d",&RECVTIMEOUT);
int time_out = RECVTIMEOUT;
//设置SO_RCVTIMEO选项
if (setsockopt(sock_listen, SOL_SOCKET, SO_RCVTIMEO, (char *) &time_out, sizeof(time_out))<0) {
puts("setsockopt error");
return -1;
}
printf("超时时间为:%d ms\n",time_out);
puts("===================================");
while (1) {
// 回射
// char buf[64];//先获取包的数量
// ZeroMemory(buf,64);
// sockaddr_in client_addr;
// int addr_len = sizeof(sockaddr_in);
// recvfrom(sock_listen,buf,64,0,(sockaddr*)&client_addr,&addr_len);
// string s=buf;
// sum=atoi(s.c_str());
// printf("%d",WSAGetLastError());
// printf("预计接收包数为:%d\n",sum);
sock_res = udpServerPacket(sock_listen);//收包
// 出错,继续其他客户端请求
// if (sock_res == -1) puts("此用户连接失败,继续其他客户端请求..");
puts("--------------");
}
// 关闭监听服务
closeConn(sock_listen);
return 0;
}
以上为服务器端代码
//丢包率测试,客户端
#define NETWORK2_2_COMM_H
#define NETWORK2_2_COMM_H
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <inaddr.h>
#include <string.h>
#pragma comment(lib, "ws2_32.lib")
#define MAXLINE 4096 // 接收缓冲区长度
#define SEVER_PORT 13131
int TIMES = 1024; // 设置客户端总的发包次数
/*套接字初始化*/
int StartUp()
{
WORD w_version = MAKEWORD(2, 2);
WSADATA wsa_data;
int res = WSAStartup(w_version, &wsa_data);
if (res != 0)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
return -1;
}//版本号错误
if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2)
{
printf("WSAStartup Error:%d\n",WSAGetLastError());
WSACleanup();
return -1;
}
return 0; //成功返回0
}
/*释放资源*/
int cleanUp()
{
int res = WSACleanup();
if (res == SOCKET_ERROR)
{
printf("WSACleanup Error:%d",WSAGetLastError());
return -1;
}
return 0;
}
/*断开连接,释放资源*/
int closeConn(SOCKET sock_conn)
{
int res = closesocket(sock_conn); //关闭连接
if (res == SOCKET_ERROR)
{
printf("关闭连接失败%d\n",WSAGetLastError());
return -1;
}
res = cleanUp();
return res;
}
/*客户端连接初始化*/
SOCKET udpClientInit(char *server_ip, u_short port, sockaddr_in &server_addr, bool flag) {
int sock_res = -1;
SOCKET sock_conn;
// 设置地址、端口
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.S_un.S_addr = inet_addr(server_ip);
//创建套接字
sock_conn = socket(AF_INET, SOCK_DGRAM, 0);
// 创建失败
if (sock_conn == INVALID_SOCKET)
{
printf("socket error:%d\n",WSAGetLastError());
cleanUp();
return -1;
}
if (flag) {//是否是连接模式
// 请求连接服务器
sock_res = connect(sock_conn, (struct sockaddr *) &server_addr, sizeof(server_addr));
// 连接 服务器失败
if (sock_res == SOCKET_ERROR)
{
printf("connect error:%d\n",WSAGetLastError());
closeConn(sock_conn);
return -1;
}
}
return sock_conn; //连接成功
}
/*数据包发送函数*/
int udpClientPacket(int times, int data_len, SOCKET sock_conn, SOCKADDR *server_addr, int addr_len) {
int sock_res, item = 0;
char send_data[MAXLINE];
memset(send_data, 1, data_len);
printf("发送包的个数:%d\n",times);
for (item = 0; item < times; ++item) {
sock_res = sendto(sock_conn, send_data, (int) strlen(send_data), 0, (SOCKADDR *) server_addr, addr_len);
if (sock_res == SOCKET_ERROR) {
puts("send error");
return -1;
}
}
return sock_res;
}
int main() {
int val;
int sock_res;
SOCKET sock_conn;
// char server_ip[] = "10.236.10.200";
char server_ip[] = "127.0.0.1";
struct sockaddr_in server_addr;
int data_len = 8;
if (StartUp() == -1) return -1; // 启动
sock_conn = udpClientInit(server_ip, SEVER_PORT, server_addr, true); //连接模式
if (sock_conn == -1) return -1;
// 连接服务器成功
puts("服务器连接成功");
printf("输入发送数据包的个数:");
scanf("%d",&TIMES);
printf("输入包长:");
scanf("%d",&data_len);
char buf[64];//先发送包的数量
ZeroMemory(buf,64);
sprintf(buf,"%d",TIMES);
// puts(buf);
val=sendto(sock_conn,buf,strlen(buf),0,(sockaddr*)&server_addr,sizeof(server_addr));
// printf("sendto return :%d %d\n",val,WSAGetLastError());
sock_res = udpClientPacket(TIMES, data_len, sock_conn, (SOCKADDR *) &server_addr, sizeof(sockaddr_in));
if (sock_res == -1) puts("客户端连接失败");
closeConn(sock_conn);
// return sock_res;
}
以上为客户端代码
一个比较好的改进的点就是增加了在客户端发送完测试包后服务器端直接输出丢包率的功能。而不是还要人去分析。