在应用层让UDP实现简单的超时重传!

转载 2007年09月14日 11:37:00

众所周知~UDP是一个无连接协议,因此靠它来传输的话是不可靠的,即使是数据包丢失也不会报错。但是,在编写Linux上的socket程序时,却可以用简单的方法,在应用层实现超时重传,让UDP可靠一些。(这次说的方法最好用于两个程序间通信——也许只能用于两台机器通信)首先~我介绍一下Linux下,I/O操作的阻塞模式:
在Linux下,I/O操作有四种模式,分别为:阻塞式I/O,非阻塞式I/O,多路复用I/O,一击信号驱动I/O,这次需要用到的是阻塞式I/O。阻塞式I/O是最简单,最常用但也是效率最低的一个。在默认模式下,所有的套接字都是阻塞模式,即:当用户调用这些函数时,函数将一直阻塞下去,直至有某个事件发生。具体事件依函数而定,比如:调用读函数,由于缓存中还没有数据,而使得读函数发生读阻塞;同理,也可能在调用写函数的时候发生写阻塞;除此之外,还有调accept函数的时候,由于没有客户连接服务器,使得其发生阻塞;调用connect函数时,由于三次握手没有结束,使得其发生阻塞等等。也就是说~在没有特定事件发生的情况下,函数将什么也不干而等待事件发生,事件发生后则继续执行程序。而有些时候,由于某些原因,会使得函数永远处于阻塞模式(比如:客户用UDP给服务器传送数据的数据丢失,使得服务器端的recvfrom函数始终处于阻塞模式)这就需要调用某些函数使这些函数不再阻塞,具体方法有:
1、使用信号:比如调用alarm函数
2、在套接字上设置SO_RCVTIMEO和SO_SNDTIMEO选项,使得其阻塞有时间限制
3、时间选择通过select函数来实现
好啦~阻塞式I/O就说到这里,言归正传~继续讨论相对可靠一些的UDP~
前面已经说了,假如使用阻塞模式,那么,当一个数据包还没有到达目的地时,那么数据包的目的端程序就会处于阻塞状态,因此不能调用sendto函数给发送端,而发送端此时也在recvfrom下阻塞了,等待对方传来消息。
由于前面已经说了,这是只有两个程序间通信,因此,双方程序的生死之大事、前途、命运……都掌握在传输的那个数据包上了,如果那个数据包不争气(没准是路由问题,线路问题等等),中途数据包丢失了,那么,双方都将永远处于阻塞状态:发送端阻塞在recvfrom上,等待接收端回话;接收端也阻塞在recvfrom上,等待发送端传来的消息。可偏偏那消息不争气,传不过来……难道这俩程序就这么挂了?
如果只有sendto,recvfrom函数而没有超时机制,那……就为这俩程序祈祷吧……大约他们俩就得挂这等关机或者被处以极刑(就是kill啊~)…………不过~听了我下面说的~就可以解决这问题~同时,让UDP层上面的应用层有超时重传的能力~(晕~我这不是作广告啊………………)
其实看到这里,大家已经多半想到了如何处理这问题:只要有一方退出阻塞模式,发个数据包,那两个程序就都解放了~怎么让一个程序退出阻塞模式呢~其实很简单啦~没错~可以用alarm函数~一旦到时间~给程序传一个SIGALRM的中断消息就可以啦~让程序先处理这消息,然后拦一下SIGALRM消息,爱怎么处理怎么处理~解决~
/****************函数:alarm函数(知道的可以不用看)****************/
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:从调用该函数算起,seconds秒后返回向调用进程传送一个SIGALRM消息
参数:seconds以秒为单位的整数
/****************************************************************/
看到这里也许你以为一切都解决了,但是还有一个容易被人忽视的问题:在Linux中,默认处理中断的方式是:
当从中断调用返回时,继续执行被中断的系统调用(用在刚才说的例子上就是:继续redvfrom……)这中默认处理方式大多数时候很有用,但是我们这里就不行了,那这个问题怎么解决呢?要解决这个问题,就不能单纯的用signal函数去设置中断处理程序了,而是要用另一个函数:sigactiong,
sigaction函数如下:
/***********函数:sigaction函数(知道的可以不用看****************/
#include <signal.h>
#include <types.h>
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact);
功能:拦截下signum消息,用act所给的方式处理,将原来的处理方式存在oldact(一般oldact设为NULL);
参数:signum:需要拦截的消息,这里是SIGALRM;
act:处理中断的方式,是一个结构体,后面会介绍这结构体;
oldact:用来存储原来的处理方式,一般为NULL,表示忽略;
/****************************************************************/
/***********结构体:struct sigaction(知道的可以不用看)*******/
struct sigaction
{
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}
成员:第一个sa_handler就是中断处理程序的入口,比如:要用alarm程序处理这个中断,就讲此值设为alarm;
sa_mask:表示在中断处理中要屏蔽的中断;
sa_flags:这是很关键的东西~它包含了一些影响中断处理过程方式的标志,具体取值如下:
SA_NOCLDSTOP:这表示如果所处理的中断是SIGCHLD,由于收到其他信号而导致了子进程终止,将不发送SIG_CHLD;
SA_ONESHOT or SA_RESETHAND:sa_handler所指向的中断处理程序只被执行一次,之后将设为默认的中断处理程序;
SA_RESTART:让被处理的系统调用在中断返回后重新执行;
SA_NOMASK or SA_NODEFFER(这就是我们要用的):在中断处理程序执行时,不平比自己的中断信号;
要考虑的成员就是上面的两个至于其他两个于要处理的问题关系不大,大家可以查书看看
/***********************************************************/
好啦~到这说的就差不多了~下面举个例子(这不是个完全的程序,只是写了我们所关心的部分)


代码: 

/*省略include*/
int main()
{
/*省略部分变量定义*/
struct sigaction alr;
memset(&alr,0,sizeof(struct sigaction));
alr.sa_handler=alarmed;/*用alarmed函数处理*/
alr.sa_flags=SA_NOMASK;/*具体含义见前文*/
alr.sa_restorer-NULL;
sigaction(SIGALRM,&alr,NULL);/*需要捕捉SIGALRM消息,具体处理方式在alr结构体中,不关心原来的处理方式*/
/*假设有一个已经设置好的struct sockaddr_in的结构体,名字是addr,和一个已经用bind函数处理完的套接字,变量名是:fd*/
for( ; ; )
{
alarm(60);/*60秒后,如果仍处于阻塞状态就重传*/
recvfrom(/*具体参数我就不说了,反正就是调用了一个recvfrom函数);*/
/*以下省略若干*/
}
}
void alarmed(int signo)
{
sendto(/*向发送端传送特殊数据包(自己定义,爱什么样什么样),当发送端收到这数据包后,就重传一遍刚才发送的数据(自然这个功能你得自己写……)*/
return;
}
/*这个程序……反正大家看懂就好啦~省略了很多检验机制……别跟我学…………*/

相关文章推荐

udp利用select实现超时重传

int maxfdp;     fd_set fds;     struct timeval timeout = {1, 0};//设置select等待3秒,3秒轮询,非阻塞就置0     wh...

tcp/ip 上,丢包重传机制

废话少说,首先,我们需要知道TCP在网络OSI的七层模型中的第四层——Transport层,IP在第三层——Network层,ARP在第二层——Data Link层,在第二层上的数据,我们叫Frame...

udp套接字及应用层udp超时重传

编写udp服务器1.注意要点: udp是无连接,不稳定,面向数据报的一种传输层协议; 既然他不可靠为什么还要用呢?其一:当应用程序使用广播或多播时只能使用UDP协议; 其二:由于他是无连接的,所以速度...

《UNIX网络编程 卷1》 笔记: UDP应用实现超时重传机制

UDP是不可靠的,它只是一直发送数据,而不管数据有没有被对方成功接收。怎样能确保发送的数据报被对方成功接收?这需要发送方和接收方共同协作。 1. 接收方成功收到数据后发送一个确认,发送方收到这个确认...

关于sigsetjmp,siglongjmp注意点 (UDP超时重传应用)

问题来源:UDP编程中,应用程序实现的超时重传机制,在计算每个分组的RTO时。在发送请求和接受应答之间要运用超时重传机制,来提高UDP传输的可靠性。 题外话:【Jacobson算法:每次测得一个RT...

一种简单的UDP网络重传机制

今天刚刚开通了CSDN博客。决定在这个满是大牛的平台上,留下自己的每一点学习过程,也在大家面前呈现自己的编程错误和误区。希望各位大牛能不惜赐教,对文章中有的错误一定要指出来,这会是我最大的收获。

libjingle源码解析(6)-【PseudoTcp】建立UDP之上的TCP(4):超时与重传

超时与重传     TCP是面向连接的可靠的运输层。当数据丢失时,TCP需要重传包。TCP通过设置定时器解决这种问题。     对每个连接,TCP有4个不同的定时器:         1)重...

UDP 超时重传机制

问题来源: 老式方法:UDP传输设定超时未N秒,发送一个请求后等待N秒钟,若超时都没有收到确认,则重发请求,重发一定次数后便丢弃。 老式方法不合理的原因:由于网络上影响因素的不同,可能RTT差别较大,...

Socket(TCP/UDP)及服务器、应用层协议(Http/FTP/SIP/Mega/SNMP)及服务器(Apache/FTPServer/SipProxy/MegaServer/SNMPServe

一、从J2SE开始(对J2SE及JVM有一个很深入的研究)推出整个Java企业级世界:   1 Socket协议(TCP/IP)及服务器:现在Java开发对网络协议处理不需要关注底层(如物理层、数据...

基于S3C2440的USB摄像头应用简单实现之应用层框架(一)

浅解基于S3C2440的USB摄像头视频采集应用之应用层框架解析(一)目的:在嵌入式系统中,视频采集主要采用两种接口:一种是标准摄像头接口,一种是USB接口(USB1.1)。标准的摄像头接口,接口复杂...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)