如何让UDP变得靠谱一些(增加UDP的可靠性)

来源:互联网 发布:通达信模拟交易软件 编辑:程序博客网 时间:2024/04/29 07:41

最近在写一个聊天系统,用到了UDP协议,但是要给UDP增加一些可靠性,终于在UNP这本书中找到了些许实现的思想,特来写写博客,与大伙交流一下思想,写的不够深入只是实现了书中所写,欢迎拍砖和留言交流!!!!!


UNP书中采用的sigsetjmp  和siglongjmp来避免 由于竟态 导致的SIGALRM
我采用的是pselect中注册了SIGALRM信号进行信号的避免同时还做到了IO多路复用

/*file_name:    udp.hathor:           WK  */#pragma once#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<errno.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<string.h>#include<signal.h>#include<sys/syscall.h>#include<pthread.h>#include<sys/socket.h>#include<sys/time.h>#include<sys/uio.h>#include<sys/un.h>#include<netinet/in.h>#include<arpa/inet.h>#include<time.h>#define MAXXMT4#define MAXLINE 1024#define RTT_RXTMIN 2#define RTT_RXTMAN 60#define RTT_MAXNREXMT 3struct r_info                                                   {                                                                       float r_rtt;                                                      float r_srtt; //  平滑化的rtt  估算因子                       float r_rttvar;   //平滑化平均偏差估算因子                                           float r_rto;    //重传超时              rto = srtt + 4*rttvar;                   int r_nrexmt;                                                   uint32_t r_tbase;                                              };    void rtt_init(struct r_info *rtt){    struct timevaltv;    gettimeofday(&tv, NULL);    rtt->r_tbase= tv.tv_sec;    rtt->r_rtt= 0;    rtt->r_rto= 3;}void rtt_newpack(struct r_info *rtt){    rtt->r_nrexmt = 0;}int rtt_start(struct r_info *rtt){    return (int)rtt->r_rto;}unsigned rtt_timestamp(struct r_info *rtt){    struct timevaltv;    gettimeofday(&tv, NULL);    return (tv.tv_sec-rtt->r_tbase)*1000+(tv.tv_usec)/1000;}void rtt_time(struct r_info *rtt, struct timeval *tv){    tv->tv_sec = rtt->r_rto;    tv->tv_usec = 0;    return;}int rtt_timeout(struct r_info *rtt){    rtt->r_rto *= 2;    if (++rtt->r_nrexmt > MAXXMT)        return (-1);    return 0;}void rtt_stop(struct r_info *rtt, unsigned sendts){    float temp = (rtt_timestamp(rtt)-sendts)/1000;    rtt->r_rtt = rtt->r_rtt*0.9 + temp*0.1;    rtt->r_rto = rtt->r_rtt*2;}static intrttinit=0;static struct r_info rtt;static struct udphdr{    unsigned seq;/* sequence */    unsigned ts;/* timestamp/ms */}hdr_send, hdr_recv;static void alarm_handler(int signo){    return;}ssize_tsend_recv(int sockfd, void *sendbuff, size_t sendbytes, void *recvbuff, size_t recvbytes,  struct sockaddr *praddr, socklen_t len){    ssize_tret;    intmaxfd;    struct timevaltv;    fd_setrset;    struct sigactionsa;    sigset_tsigset_alarm, sigset_empty;    struct msghdrmsg_send, msg_recv;    struct ioveciov_send[2], iov_recv[2];    if (rttinit == 0)    {        rtt_init(&rtt);        rttinit = 1;    }memset(&msg_send, 0x00, sizeof(struct msghdr));memset(&msg_recv, 0x00, sizeof(struct msghdr));    iov_send[0].iov_base= &hdr_send;iov_send[0].iov_len= sizeof(struct udphdr);   iov_send[1].iov_base= sendbuff;    iov_send[1].iov_len= sendbytes;    iov_recv[0].iov_base= &hdr_recv;    iov_recv[0].iov_len= sizeof(struct udphdr);    iov_recv[1].iov_base= recvbuff;    iov_recv[1].iov_len= recvbytes;    msg_send.msg_name= praddr;    msg_send.msg_namelen= len;    msg_send.msg_iov= iov_send;    msg_send.msg_iovlen= 2;    msg_recv.msg_name= praddr;    msg_recv.msg_namelen= len;    msg_recv.msg_iov= iov_recv;    msg_recv.msg_iovlen= 2;    hdr_send.seq++;/* 该次数据包发送序列号 */    sigemptyset(&sigset_alarm);    sigemptyset(&sigset_empty);    sigaddset(&sigset_alarm, SIGALRM);    sa.sa_handler= alarm_handler;    sa.sa_flags= 0;    sigemptyset(&sa.sa_mask);    if (sigaction(SIGALRM, &sa, NULL) < 0)    {        perror("sigaction");        return -1;    }    rtt_newpack(&rtt);    FD_ZERO(&rset);    while(1)    {        hdr_send.ts = rtt_timestamp(&rtt);        if ((ret = sendmsg(sockfd, &msg_send, 0)) < 0)        {            perror("sendmsg");            return -1;        }        alarm(rtt_start(&rtt));loop:        FD_SET(sockfd, &rset);        sigprocmask(SIG_BLOCK, &sigset_alarm, NULL);        if ((ret = pselect(sockfd+1, &rset, NULL, NULL, NULL, &sigset_empty)) < 0)        {            if (errno == EINTR)            {                if (rtt_timeout(&rtt) < 0)/* limit */                {                    rttinit = 0;                    errno = ETIMEDOUT;                    return (-1);                }                /* send again */                continue;            }        }        if (FD_ISSET(sockfd, &rset))        {            if ((ret = recvmsg(sockfd, &msg_recv, 0)) < 0)            {                perror("recvmsg");                goto loop;            }            if (ret < sizeof(struct udphdr) || hdr_recv.seq != hdr_send.seq)            {                goto loop;            }            rtt_stop(&rtt, hdr_send.ts);            return ret-sizeof(struct udphdr);        }    }}

/*file_name:    udp.cathor:           WK  */#include"udp.h"void echo(int sockfd, struct sockaddr *praddr, socklen_t len){    intret;    char sendline[MAXLINE];char recvline[MAXLINE];    memset(sendline, 0x00, MAXLINE);while (fgets(sendline, MAXLINE, stdin) != NULL)    {    memset(recvline, 0x00, MAXLINE);        if ((ret = send_recv(sockfd, sendline, strlen(sendline), recvline, MAXLINE, praddr, len)) <=0)        {            printf("perr close\n");            return;        }        recvline[ret] = 0;        fputs(recvline, stdout);       memset(sendline, 0x00, MAXLINE);    }}int main(int argc, char *argv[]){    int connfd;    struct sockaddr_in servaddr;    if ((connfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)    {        perror("socket");        exit(-1);    }    memset(&servaddr, 0x00, sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_port = htons(8002);    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");    echo(connfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in));    close(connfd);    return 0;} 





1 0
原创粉丝点击