給UDP增加可靠性

來源:互聯網
上載者:User

給UDP增加可靠性


刺蝟@http://blog.csdn.net/littlehedgehog

 

 

 

UNP裡面的例子程式,把計算rtt的演算法改了下,參考的TCP/IP詳解裡面介紹的一個稍微簡單的演算法,另外,不喜歡setjmp這種編程模式,感覺程式碼可讀性較差,最後還是改成使用pselect+signal,這樣代碼會清晰些。

 

 

 

下面是主函數

 

#include "./unix.h"<br />#include "./rtt.h"<br />static intrttinit;<br />static struct r_info rtt;<br />static struct udphdr<br />{<br /> unsigned seq;/* sequence */<br /> unsigned ts;/* timestamp/ms */<br />}hdr_send, hdr_recv;<br />static void alarm_handler(int signo)<br />{<br /> return;<br />}<br />ssize_tsend_recv(int sockfd, void *sendbuff, size_t sendbytes, void *recvbuff, size_t recvbytes, const struct sockaddr *praddr, socklen_t len)<br />{<br /> ssize_tret;<br /> intmaxfd;<br /> struct timevaltv;<br /> fd_setrset;<br /> struct sigactionsa;<br /> sigset_tsigset_alarm, sigset_empty;<br /> struct msghdrmsg_send, msg_recv;<br /> struct ioveciov_send[2], iov_recv[2];<br /> if (!rttinit)<br /> {<br /> rttinit = 1;<br /> rtt_init(&rtt);<br /> }<br />memset(&msg_send, 0x00, sizeof(struct msghdr));<br />memset(&msg_recv, 0x00, sizeof(struct msghdr));<br /> iov_send[0].iov_base= &hdr_send;<br />iov_send[0].iov_len= sizeof(struct udphdr);<br /> iov_send[1].iov_base= sendbuff;<br /> iov_send[1].iov_len= sendbytes;<br /> iov_recv[0].iov_base= &hdr_recv;<br /> iov_recv[0].iov_len= sizeof(struct udphdr);<br /> iov_recv[1].iov_base= recvbuff;<br /> iov_recv[1].iov_len= recvbytes;<br /> msg_send.msg_name= praddr;<br /> msg_send.msg_namelen= len;<br /> msg_send.msg_iov= iov_send;<br /> msg_send.msg_iovlen= 2;<br /> msg_recv.msg_name= praddr;<br /> msg_recv.msg_namelen= len;<br /> msg_recv.msg_iov= iov_recv;<br /> msg_recv.msg_iovlen= 2;<br /> hdr_send.seq++;/* 該次資料包發送序號 */<br /> sigemptyset(&sigset_alarm);<br /> sigemptyset(&sigset_empty);<br /> sigaddset(&sigset_alarm, SIGALRM);<br /> sa.sa_handler= alarm_handler;<br /> sa.sa_flags= 0;<br /> sigemptyset(&sa.sa_mask);<br /> if (sigaction(SIGALRM, &sa, NULL) < 0)<br /> {<br /> perror("sigaction");<br /> return;<br /> }<br /> rtt_newpack(&rtt);<br /> FD_ZERO(&rset);<br /> for ( ; ; )<br /> {<br /> hdr_send.ts = rtt_timestamp(&rtt);<br /> if ((ret = sendmsg(sockfd, &msg_send, 0)) < 0)<br /> {<br /> perror("sendmsg");<br /> return;<br /> }<br /> alarm(rtt_start(&rtt));<br />loop:<br /> FD_SET(sockfd, &rset);<br /> sigprocmask(SIG_BLOCK, &sigset_alarm, NULL);<br /> if ((ret = pselect(sockfd+1, &rset, NULL, NULL, NULL, &sigset_empty)) < 0)<br /> {<br /> if (errno == EINTR)<br /> {<br /> if (rtt_timeout(&rtt) < 0)/* limit */<br /> {<br /> rttinit = 0;<br /> errno = ETIMEDOUT;<br /> return (-1);<br /> }<br /> /* send again */<br /> continue;<br /> }<br /> }<br /> if (FD_ISSET(sockfd, &rset))<br /> {<br /> if ((ret = recvmsg(sockfd, &msg_recv, 0)) < 0)<br /> {<br /> perror("recvmsg");<br /> goto loop;<br /> }<br /> if (ret < sizeof(struct udphdr) || hdr_recv.seq != hdr_send.seq)<br /> {<br /> goto loop;<br /> }<br /> rtt_stop(&rtt, hdr_send.ts);<br /> return ret-sizeof(struct udphdr);<br /> }<br /> }<br />}<br />void echo(int sockfd, struct sockaddr *praddr, socklen_t len, struct FILE *fp)<br />{<br /> intret;<br /> charsendline[MAXLINE], recvline[MAXLINE];<br /> memset(sendline, 0x00, MAXLINE);<br /> memset(recvline, 0x00, MAXLINE);<br /> while (fgets(sendline, MAXLINE, fp) != NULL)<br /> {<br /> if ((ret = send_recv(sockfd, sendline, strlen(sendline), recvline, MAXLINE, praddr, len)) < 0)<br /> {<br /> return;<br /> }<br /> recvline[ret] = 0;<br /> fputs(recvline, stdout);<br /> }<br />}<br />int main(int argc, char *argv[])<br />{<br /> int connfd;<br /> struct sockaddr_in servaddr;<br /> if ((connfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)<br /> {<br /> perror("socket");<br /> exit(-1);<br /> }<br /> memset(&servaddr, 0x00, sizeof(servaddr));<br /> servaddr.sin_family = AF_INET;<br /> servaddr.sin_port = htons(1988);<br /> servaddr.sin_addr.s_addr = inet_addr("210.32.34.137");<br /> echo(connfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in), stdin);<br /> close(connfd);<br /> return 0;<br />} 

 

rtt.c

 

#include "./unix.h"<br />#include "./rtt.h"<br />#define MAXXMT4<br />void rtt_init(struct r_info *rtt)<br />{<br /> struct timevaltv;<br /> gettimeofday(&tv, NULL);<br /> rtt->r_tbase= tv;<br /> rtt->r_rtt= 0;<br /> rtt->r_rto= 3;<br />}<br />void rtt_newpack(struct r_info *rtt)<br />{<br /> rtt->r_rexmt = 0;<br />}<br />int rtt_start(struct r_info *rtt)<br />{<br /> return (int)rtt->r_rto;<br />}<br />unsigned rtt_timestamp(struct r_info *rtt)<br />{<br /> struct timevaltv;<br /> gettimeofday(&tv, NULL);<br /> return (tv.tv_sec-rtt->r_tbase.tv_sec)*1000+(tv.tv_usec-rtt->r_tbase.tv_usec)/1000;<br />}<br />void rtt_time(struct r_info *rtt, struct timeval *tv)<br />{<br /> tv->tv_sec = rtt->r_rto;<br /> tv->tv_usec = 0;<br /> return;<br />}<br />int rtt_timeout(struct r_info *rtt)<br />{<br /> rtt->r_rto *= 2;<br /> if (++rtt->r_rexmt > MAXXMT)<br /> return (-1);<br /> return 0;<br />}<br />void rtt_stop(struct r_info *rtt, unsigned sendts)<br />{<br /> float temp = (rtt_timestamp(rtt)-sendts)/1000;<br /> rtt->r_rtt = rtt->r_rtt*0.9 + temp*0.1;<br /> rtt->r_rto = rtt->r_rtt*2;<br />}<br />



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.