Linux下利用epoll实现两台机器之间的UDP传输丢包统计

公司机房到阿里云的数据传输有时候会出现丢包,所以需要程序来进行查询和排查,公司前辈写了一个程序来进行机器之间的丢包统计。
服务器:pong.cpp

#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define MAXLINE 1500
#define SERV_PORT 2019    //服务器端口号


void do_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen)
{
    int n, jzq_num = 0;
    socklen_t len;
    char mesg[MAXLINE];
    int i ;


    for(;;)
    {
        len = clilen;
        /* waiting for receive data */
        n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
        mesg[n]=0;
        printf("recvfrom data:%d %d\n",n, ++jzq_num);
        printf("%s\n",mesg);
        /* sent data back to client */
        sendto(sockfd, mesg, n, 0, pcliaddr, len);
    }
}


int main(int argc,char *argv[])
{
    int sockfd;
    int m_port = SERV_PORT;
    int result, buf_len;
    int len = sizeof (buf_len);
    struct sockaddr_in servaddr, cliaddr;

    if (argc >=2) sscanf(argv[1],"%d",&m_port);

    sockfd = socket(AF_INET, SOCK_DGRAM, 0); /* create a socket */


    /* init servaddr */
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(m_port);

    printf("port:%d\n", m_port);


    result = getsockopt((unsigned int)sockfd, SOL_SOCKET, SO_RCVBUF, (char *)&buf_len, (socklen_t *)&len);
    printf ("one:getsock_recvbuf-> result:%s buf_len:%d\n", result?"NO":"YES", buf_len);

    if(result == 0 && buf_len < 1024*1024)
    {
        buf_len = 1024*1024;

        setsockopt((unsigned int)sockfd, SOL_SOCKET, SO_RCVBUF, (char *)&buf_len, len);  //接收缓冲区大小为1MB
        printf ("setsock_recvbuf-> result:%s buf_len:%d\n", result?"NO":"YES", buf_len);

        result = getsockopt((unsigned int)sockfd, SOL_SOCKET, SO_RCVBUF, (char *)&buf_len, (socklen_t *)&len);
        printf ("two:getsock_recvbuf-> result:%s buf_len:%d\n", result?"NO":"YES", buf_len);
    }

    /* bind address and port to socket */
    if(bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
    {
        perror("bind error");
        exit(1);
    }
    printf("UPD servese is bind success and do_echo now\n");
    do_echo(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));


    return 0;
}

测试程序check.cpp

#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/time.h>

#define MAXSIZE     1024
#define FDSIZE      1024
#define EPOLLEVENTS 20

#define SERV_PORT   (9999)//你需要连接的服务器端口号
#define LOCAL_PORT  (0)    //UDP传输端口,0表示系统分配
#define WAIT_TIME   (100)

static int handle_connection(int sockfd, struct sockaddr_in *servaddr, int flag);
static int handle_events(int epollfd,struct epoll_event *events,int num,int sockfd,char *buf, struct sockaddr_in *servaddr);
static int do_read(int epollfd,int fd,int sockfd,char *buf, struct sockaddr_in *servaddr);
static void add_event(int epollfd,int fd,int state);
static void delete_event(int epollfd,int fd,int state);
static void modify_event(int epollfd,int fd,int state);


char send_buf[MAXSIZE];
char ip[50];

int check(char *ip, int port, int flag)
{
    int sockfd;
    struct sockaddr_in  servaddr;
    struct sockaddr_in  clientaddr;
    int res ;

    sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(port);
    servaddr.sin_addr.s_addr = inet_addr(ip);

    bzero(&clientaddr, sizeof(clientaddr));
    clientaddr.sin_family = AF_INET;
    clientaddr.sin_port = htons(LOCAL_PORT);
    clientaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    if(bind(sockfd, (struct sockaddr *)&clientaddr, sizeof(clientaddr)) == -1) 
    {   
        perror("bind error");
        exit(1);
    }

    sockaddr_in addrMy;
    memset(&addrMy,0,sizeof(addrMy));
    int leng = sizeof(addrMy);

    if (getsockname(sockfd, (sockaddr*)&addrMy, (socklen_t*)&leng) != 0)
    {
       puts("Getsockname Error!");
       return 0;
    }
    printf("Current Socket PORT->%d ",ntohs(addrMy.sin_port)); 
    fflush(stdout);
    res = handle_connection(sockfd, &servaddr, flag);
    close(sockfd);
    return res;
}

void print_cur_time()
{
     time_t timep;
     struct tm *p;
     time(&timep);
     p = localtime(&timep); //取得当地时间
     printf ("%d-%02d-%02d %02d:%02d:%02d ",(1900+p->tm_year), (1+p->tm_mon), p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
     fflush(stdout);
}

int main(int argc,char *argv[])
{
  FILE *fp;
  int num = 0, lost_num = 0;
  while(1)
  {
    fp = fopen("./home/jzq/Check/poxy.txt*/", "r");//自己创目录文件,poxy.txt里是要连的ip地址
    if(fp == NULL)
    {
        printf("The poxy.txt not exit\n");
       return 0;
    }
    while(~fscanf(fp, "%s", ip))
    {
        print_cur_time();
        printf("ALY -> %s ", ip);
        fflush(stdout);
        check(ip, SERV_PORT, 2);
        sleep(0.1);
    }
    fclose(fp);
  }
  return 0;
}


static int handle_connection(int sockfd, struct sockaddr_in *servaddr, int flag)
{
    int epollfd;
    struct epoll_event events[EPOLLEVENTS];
    int ret, len, num = 30;
    int lost_num =0;
    epollfd = epoll_create(FDSIZE);
    add_event(epollfd,sockfd,EPOLLIN);
    while(num--)
    {
        len = 20;              //包长,可以按需要增大,但要注意传输时间要相应增大
        memset(send_buf, '6', len);
        send_buf[len] = 0;

        if(sendto(sockfd, send_buf, len, 0, (struct sockaddr*)servaddr, sizeof(struct sockaddr_in)) <= 0)
    {
        printf("sendto error");
        continue;
    }

        ret = epoll_wait(epollfd, events, epollevents, wait_time);
        if(ret > 0 && (len = handle_events(epollfd, events, ret, sockfd, send_buf, servaddr)) > 0)
    {
            if(!len)
                printf("unkonw\n");
    }
    else
        {
            lost_num++; 
            printf(".");
            fflush(stdout);
        }
    }
    close(epollfd);
    printf("lost:%d%\n", lost_num*100/30);
    return lost_num;
}

static int handle_events(int epollfd,struct epoll_event *events,int num,int sockfd,char *buf, struct sockaddr_in *servaddr)
{
    int fd;
    int i;
    for (i = 0;i < num;i++)
    {
        fd = events[i].data.fd;
        if ((events[i].events & EPOLLIN) && (fd == sockfd))
            return do_read(epollfd,fd,sockfd,buf, servaddr);
    }
    return -1;
}

static int do_read(int epollfd,int fd,int sockfd,char *buf, struct sockaddr_in *servaddr)
{
    socklen_t len = sizeof(struct sockaddr_in);
    return recvfrom(sockfd, buf, MAXSIZE, MSG_DONTWAIT, (struct sockaddr *)servaddr, &len);
}

static void add_event(int epollfd,int fd,int state)
{
    struct epoll_event ev;
    ev.events = state;
    ev.data.fd = fd;
    epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&ev);
}

static void delete_event(int epollfd,int fd,int state)
{
    struct epoll_event ev;
    ev.events = state;
    ev.data.fd = fd;
    epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,&ev);
}

static void modify_event(int epollfd,int fd,int state)
{
    struct epoll_event ev;
    ev.events = state;
    ev.data.fd = fd;
    epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&ev);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值