分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
给UDP增加可靠性
刺猬@http://blog.csdn.net/littlehedgehog
UNP里面的例子程序,把计算rtt的算法改了下,参考的TCP/IP详解里面介绍的一个稍微简单的算法,另外,不喜欢setjmp这种编程模式,感觉程序代码可读性较差,最后还是改成使用pselect+signal,这样代码会清晰些。
下面是主函数
- #include "./unix.h"
- #include "./rtt.h"
- static int rttinit;
- 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_t send_recv(int sockfd, void *sendbuff, size_t sendbytes, void *recvbuff, size_t recvbytes, const struct sockaddr *praddr, socklen_t len)
- {
- ssize_t ret;
- int maxfd;
- struct timeval tv;
- fd_set rset;
- struct sigaction sa;
- sigset_t sigset_alarm, sigset_empty;
- struct msghdr msg_send, msg_recv;
- struct iovec iov_send[2], iov_recv[2];
- if (!rttinit)
- {
- rttinit = 1;
- rtt_init(&rtt);
- }
- 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;
- }
- rtt_newpack(&rtt);
- FD_ZERO(&rset);
- for ( ; ; )
- {
- hdr_send.ts = rtt_timestamp(&rtt);
- if ((ret = sendmsg(sockfd, &msg_send, 0)) < 0)
- {
- perror("sendmsg");
- return;
- }
- 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);
- }
- }
- }
- void echo(int sockfd, struct sockaddr *praddr, socklen_t len, struct FILE *fp)
- {
- int ret;
- char sendline[MAXLINE], recvline[MAXLINE];
- memset(sendline, 0x00, MAXLINE);
- memset(recvline, 0x00, MAXLINE);
- while (fgets(sendline, MAXLINE, fp) != NULL)
- {
- if ((ret = send_recv(sockfd, sendline, strlen(sendline), recvline, MAXLINE, praddr, len)) < 0)
- {
- return;
- }
- recvline[ret] = 0;
- fputs(recvline, stdout);
- }
- }
- 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(1988);
- servaddr.sin_addr.s_addr = inet_addr("210.32.34.137");
- echo(connfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in), stdin);
- close(connfd);
- return 0;
- }
rtt.c
- #include "./unix.h"
- #include "./rtt.h"
- #define MAXXMT 4
- void rtt_init(struct r_info *rtt)
- {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- rtt->r_tbase = tv;
- rtt->r_rtt = 0;
- rtt->r_rto = 3;
- }
- void rtt_newpack(struct r_info *rtt)
- {
- rtt->r_rexmt = 0;
- }
- int rtt_start(struct r_info *rtt)
- {
- return (int)rtt->r_rto;
- }
- unsigned rtt_timestamp(struct r_info *rtt)
- {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return (tv.tv_sec-rtt->r_tbase.tv_sec)*1000+(tv.tv_usec-rtt->r_tbase.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_rexmt > 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;
- }