当前位置:天才代写 > tutorial > C语言/C++ 教程 > UDP实现简朴的超时重传

UDP实现简朴的超时重传

2017-11-03 08:00 星期五 所属: C语言/C++ 教程 浏览:797

副标题#e#

众所周知~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以 秒为单元的整数

/****************************************************************/


#p#副标题#e#

看到这里也许你觉得一切都办理了,可是尚有一个容易被人忽视的问题:在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(这就是 我们要用的):在间断处理惩罚措施执行时,不服比本身的间断信号;

要思量的成员就是 上面的两个至于其他两个于要处理惩罚的问题干系不大,各人可以查书看看

/***********************************************************/

#p#副标题#e#

好啦~ 到这说的就差不多了~下面举个例子(这不是个完全的措施,只是写了我们所体贴的部门)

代码:

#p#分页标题#e#

 

/*省略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;
}
/*

 

这个措施……横竖各人看懂就好啦~省略了许多检讨机制 ……别跟我学…………*/

 

    关键字:

天才代写-代写联系方式