如何让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
- 如何让UDP变得靠谱一些(增加UDP的可靠性)
- 给UDP增加可靠性
- 如何提高UDP的可靠性
- UDP可靠性的增加之UNP22章读后感(一)
- UNIX udp应用增加可靠性(1)
- udp 如何实现可靠性
- udp如何实现可靠性传输?
- udp如何实现可靠性传输?
- udp如何实现可靠性传输?
- udp如何实现可靠性传输?
- UDP网络通讯/UDP可靠性实现
- UDP套接字编程以及提高UDP可靠性的方法
- 如何让UDP也可靠
- 让你的飞秋死个机(UDP)
- 理解 TCP 和 UDP(五)TCP 可靠性交付的实现
- 如何让UDP实现可靠传输
- 如何让UDP实现可靠传输
- 如何让UDP实现可靠传输
- 程序报错:cannot resolve symbol R
- FineUI Gird单元格编辑 保存新增的一行到数据库 LINQ
- 简单缓存的实现,相当牛叉!自己看吧,只有50行代码。
- linux命令:cp 命令
- win7怎么创建SSH key链接github仓库,解决:git error: couldn't connect to host
- 如何让UDP变得靠谱一些(增加UDP的可靠性)
- MIPS 通用寄存器
- Maven项目中遇到的奇葩问题
- App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Te
- Android-->Rxjava与Retrofit2的结合实战
- python 利用sklearn自带的模块 快速简单实现文章的 tfidf向量空间的表示
- Wincc7.3学习之——如何建立起数据库链接
- Lua笔记12 metatable 和metamethod
- MySQL权限篇之ALL与SUPER