[url]http://www.linuxsir.org/bbs/showthread.php?t=46066[/url]
众所周知~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; } /*这个程序……反正大家看懂就好啦~省略了很多检验机制……别跟我学…………*/

转载于:https://blog.51cto.com/qq164587043/155144

UDP实现简单的超时重传相关推荐

  1. TCP协议-TCP超时重传机制

    一.前言 在TCP通信中,既要保证在网络正常的情况下提供可靠的交付服务,又要保证在网络异常的情况下也提供可靠的交付服务.而TCP的超时重传机制就是解决在网络异常情况下的可靠传输问题的. 二.通过序列号 ...

  2. TCP可靠传输:ARQ协议(停止等待、超时重传、滑动窗口、回退N帧、选择重传)

    ARQ(Automatic Repeat-reQuest,自动重传请求) 一. ARQ简介 二. 停止等待ARQ (1)正常传输 (2)传输出现差错 1. 超时重传 2. 编号 (3)信道利用率 三. ...

  3. 对TCP和UDP的简单理解——通俗易懂,图文并茂

    前言 tcp协议和udp协议都在传输层工作,他们的目标都是在程序之间传输数据(可是文本,图片,视频)对于tcp和udp都是二进制数. TCP和UDP之间的区别是什么? TCP是基于连接的,而UDP是基 ...

  4. TCP之超时重传机制

    TCP协议是一种面向连接的可靠的传输层协议,它保证了数据的可靠传输,对于一些出错.超时丢包等问题TCP设计了超时重传机制,其基本原理:在发送一个数据之后,就开启一个定时器,若是在这个时间内没有收到发送 ...

  5. TCP/IP学习笔记(四)TCP超时重传及拥塞控制

    TCP是可靠的传输层协议,但这并不意味着一端发送的数据一定可以到达另一端,因为传输过程中遇到的情况是不可控的,很有可能就有某些数据发生丢失,所以"可靠"其实并不可靠. 不过毕竟现如 ...

  6. TCP/IP协议栈:TCP超时重传机制

    目录 基础概念 重传超时时间RTO RTO的设定 连接往返时间RTT RTT的计算 Karn算法 往返时间测量 重传 拥塞避免算法 快速重传和快速恢复算法 重新分组 网络数据包丢失,重传和重复确认 是 ...

  7. 倍福PLC--C#实现ADS通信超时重传设定

    本文介绍倍福PLC–C#实现ADS通信超时重传设定 在Beckhoff TwinCAT 系统中,各个软件模块(如TwinCAT PLC.TwinCAT NC.Windows 应用程序等)的工作模式类似 ...

  8. 计算机网络超时重传时间,TCP超时重传机制

    超时重传是TCP协议保证数据可靠性的另一个重要机制,其原理是在发送某一个数据以后就开启一个计时器,在一定时间内如果没有得到发送的数据报的ACK报文,那么就重新发送数据,直到发送成功为止.[1] 中文名 ...

  9. 网络原理 --- 传输层Ⅱ TCP协议中的确认应答,超时重传和连接管理

    文章目录 网络原理 传输层 TCP 协议 TCP的基本特性 1.确认应答 2.超时重传 3.连接管理 ❗❗①建立连接(三次握手) ②断开连接(四次挥手) 总结 网络原理 介绍TCP/IP协议中每一层里 ...

  10. TCP协议--带外数据和超时重传

    <Linux高性能服务器编程>阅读笔记: 1. 带外数据   有些传输层协议具有带外(Out Of Band, OOB)数据的概念,用于迅速告知对方本端发生的重要事件.因此带外数据比普通数 ...

最新文章

  1. 有关Run-Time Check Failure #2 - Stack around the variable 'XXX' was corrupted.错误的解决方法
  2. emc celerra(一)--界面概览
  3. python3-python3--内置函数
  4. Django rest_framework 实用技巧
  5. Python之Time模块
  6. [PAT乙级]1007 素数对猜想
  7. Windows SDK笔记(三):定制控件消息处理函数
  8. 分布式块设备复制:客户端
  9. 会c语言如何快速入门python,初学者如何从C语言到Python的转化(北大陈斌老师的举例 )...
  10. [No000011A]Office Excel设置显示日期与星期
  11. Java项目-食堂菜品点评系统(SpringBoot + SpringSecurity + Thymeleaf + Redis)
  12. 整人电脑BAT小程序源码大全
  13. html文本框虚线并加上文字,文字边框虚线样式用css怎么写?(示例)
  14. Unity获取本机IP地址
  15. 参加了一场温州游资的婚礼,也太壕了
  16. HDU - 6070 线段树 + 分数规划
  17. android获取指定位置经纬度,Android - 如何获取当前位置(经度和纬度)?
  18. php 域名被劫持,域名被劫持怎么办
  19. windows如何查看电脑开关机记录
  20. 更多丰富内容,请转移至博主的个人博客——SeaDream乄造梦

热门文章

  1. 自定义Kettle数据库插件 1
  2. 【Python学习笔记】集合set
  3. Android开发指南(39) —— Testing Fundamentals
  4. Matlab设置字体大小
  5. SharePoint2013 App 开发中 自定义网站栏,内容类型,列表。
  6. windows和linux之间共享文件 samba的使用
  7. 计算机组成原理输入实验报告,计算机组成原理实验 实验报告.doc
  8. python抖音表白软件手机版,我喜欢你 抖音表白程序python版
  9. 西门子触摸屏中显示HTML,西门子触摸屏上传问题
  10. 水利工程中计算机软件用到什么,水利工程设计中计算机技术的应用论文