Linux网络编程----UDP编程基础知识

2023-05-16

UDP概述

UDP 是 User Datagram Protocol 的简称, 中文名是用户数据报协议,是一个简单的面向数据报的传输层协议,在网络中用于处理数据包,是一种无连接的协议。UDP 不提供可靠性的传输,它只是把应用程序传给 IP 层的数据报发送出去,但是并不能保证它们能到达目的地。由于 UDP 在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。

UDP编程C/S结构

在这里插入图片描述

udp编程中的常用函数

1、sendto()函数的使用

#include <sys/types.h>

#include <sys/socket.h>

ssize_t  sendto(int   sockfd,  const  void  *  buf,  size_t   len ,  int   flags,  const  struct sockaddr  *  dest_addr ,  socklen_t   addrlen);

(1)功能:向指定的数据接收端发送指定的数据。

(2)返回值:成功,返回实际发送的字节数。失败,返回-1.

(3)参数:

     ----sockfd:发送操作使用的套接字文件描述符

     -----buf:要发送的数据在内存中的首地址

    -----len:要发送的数据的长度

    ------flags:发送标志,一般为0

    ------dest_addr:数据接收端的地址(包含IP地址和端口号)的结构体指针

    -------addrlen:数据接收端地址结构体的大小

2、recvfrom()函数的使用

#include <sys/types.h>

#include <sys/socket.h>

ssize_t   recvfrom(int sockfd,  void  *  buf ,  size_t  len ,  int   flags ,  struct sockaddr  *  src_addr,   socklen_t   *   addrlen);

(1)功能:接收数据发送端到达的数据

(2)返回值:成功,返回实际接收到的字节数。失败返回-1

(3)参数:

     -----sockfd:接收操作使用的套接字文件描述符

     -----buf:接收到的数据存放在内存中的位置

    ------len:指buf缓冲区的大小,即期望接收的最大数据的长度

    -----flags:接收标志,一般为0

    -----src_addr:指向的结构体将被数据发送端的地址(含IP地址和端口号)所填充

   -----addrlen:所指向的存储位置,调用前应填入src_addr和addrlen的结构体大小,调用后则将被填入发送端的地址的实际大小

  备注:若不需要发送端的IP地址和端口号,可以将src_addr和addrlen都设置为NULL

i/o模型和多路复用

在linux/unix下主要有4种I/O模型:

  • 阻塞I/O:最常用
  • 非阻塞I/O:可防止进程阻塞在I/O操作上,需要轮询
  • I/O 多路复用:允许同时多个I./0进行控制
  • 信号驱动I/O:一种异步通信模型

阻塞I/O模式

阻塞I/O模式是最普遍使用的I/O模式,大部分程序使用的都是阻塞模式的i/o
缺省情况下,套接字建立后所处于的模式就是阻塞I/O模式,很多读写函数在调用过程中会发生阻塞;
许多函数在调用过程中都会发生阻塞:

  • 读操作中的read,recv,recvfrom
  • 写操作中的:write,send【sendto不阻塞
  • 其他操作中的:accept,connect

阻塞基本原理

读阻塞
以read为例:

  • 进程调用read函数从套接字上读取数据,当套接字的接受缓冲区中还没有数据可读,函数read将会发生阻塞
  • 他会一直阻塞下去,等待套接字的接受缓冲区中有数据可读,
  • 经过一段时间后,缓冲区内接受到数据,于是内核边去唤醒该进程,通过read访问这些数据
  • 如果在进程阻塞过程中,对方发生故障,那这个进程将永远阻塞下去
    在这里插入图片描述

写阻塞

  • 在写操作是发生阻塞的情况要比读操作少,主要发生在要写入的缓冲区的大小小于要写入的数据量的情况下。
  • 这时,写操作不进行热河的拷贝工作,将发生阻塞
  • 一旦发送缓冲区有足够的空间,内核将唤醒进程,将数据从用户缓冲区拷贝到相应的发送数据缓冲区。
  • UDP不用等待确认,没有实际的发送缓冲区,所以UDP协议汇总不存在发送缓冲区满的情况,在udp套接字上的执行操作永远也不会阻塞

非阻塞模式I/O

  • 当我们将一个套接字设置为非阻塞模式,我们相当于告诉了系统内核"当我请求的I/O操作不能马上完成,你想让我们的进程进行休眠等待时,不要这么做,请返回一个错误给我"。
  • 当一个应用程序是用来非阻塞模式的套接字,它需要使用一个循环来不停地测试是否一个文件描述符数据可读(polling)
  • 应用程序不停地polling 内核来检查是否I/O操作已经就绪,这将是一个季度浪费CPU资源的操作
  • 这种模式使用不普遍

非阻塞模式的实现

fcnl()函数

  • 当你看是建立一个套接字描述符的时候,系统内核将其设置为阻塞io模式,

  • 可以使用函数fcnl()设置一个套接字的标志位0_NONBLOCK来实现阻塞

  • 代码实现:

  • 1.fcnl()函数实现

int fcnl(nt fd, int cmd,long arg)int flag;
falg=fcntl(sockfd, F_GETEL 0);
flag |=0_NONBLOCK;
fcnl(sockefd,F_SETEL,flag);
  • 2.ioct1()函数实现
int b_on=1ioct1(sock_fd,FIONBIO,&b_on);

多路复用I/O

  • 应用程序中同时处理多路输入输出流,若采用阻塞模式,将得不到预期的目的。

  • 若采用非阻塞模式,对多个输入进行轮询,但又台浪费CPU时间;

  • 若设置多个进程,分别处理一条数据通路,将新产生进程间的同步与通信问题,使程序变得更加复杂。

  • 比较好的方法就是使用I/O复用,其基本思想是:

    • 先构造一张描述符的表,然后调用一个函数,当这些文件描述符中的一个或者多个已经准备好进行I/O时函数才返回
    • 函数返回时告诉进程那个描述符已经就绪,可以进行I/O操作。

基本常识:
linux每个进程默认最多可以打开1024个文件,最多有1024个文件描述符
文件描述符的特点:

  • 非负整数
  • 从最小可用的数字分配
  • 每个进程启动时默认打开0,1,2三个文件描述符
    多路复用针对布置套接字fd,也针对普通的文件描述fd

select函数

使用select函数可以完成非阻塞方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。
非阻塞方式:non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生,则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高。

设置文件描述符

select可以同时监视多个文件描述符(套接字)。
此时需要先将文件描述符集中到一起。集中时也要按照监视项(接收,传输,异常)进行区分,即按照上述3种监视项分成三类。
使用fd_set数组变量执行此项操作,该数组是存有0和1的位数组。
数组是从下标0开始,最左端的位表示文件描述符0。如果该位值为1,则表示该文件描述符是监视对象。
“是否应当通过文件描述符的数字直接将值注册到fd_set变量?”
当然不是!操作fd_set的值由如下宏来完成:

FD_ZERO(fd_set* fdset):=将fd_set变量的所有位初始化为0。FD_SET(int fd, fd_set* fdset):在参数fd_set指向的变量中注册文件描述符fd的信息。
FD_CLR(int fd, fd_set* fdset):参数fd_set指向的变量中清除文件描述符fd的信息。
FD_ISSET(int fd, fd_set* fdset):若参数fd_set指向的变量中包含文件描述符fd的信息,则返回真。

设置监视范围及超时

select函数:

#include <sys/select.h>
#include <sys/time.h>
int select(int maxfd, fd_set* readset, fd_set* writeset, fd_set* exceptset, 
const struct timeval* timeout);

select函数共有5个参数,其中参数和返回值:
maxfd:监视对象文件描述符数量。
readset:将所有关注“是否存在待读取数据”的文件描述符注册到fd_set变量,并传递其地址值。
writeset: 将所有关注“是否可传输无阻塞数据”的文件描述符注册到fd_set变量,并传递其地址值。
exceptset:将所有关注“是否发生异常”的文件描述符注册到fd_set变量,并传递其地址值。
timeout:调用select后,为防止陷入无限阻塞状态,传递超时信息。
返回值:错误返回-1,超时返回0。当关注的事件返回时,返回大于0的值,该值是发生事件的文件描述符数。

select函数用来验证3种监视项的变化情况。根据监视项声明3个fd_set变量,分别向其注册文件描述符信息,并把变量的地址传递到函数的第二到第四个参数。但是,在调用select函数前需要决定2件事:
“文件描述符的监视范围是?”
“如何设定select函数的超时时间?”

第一,文件描述符的监视范围与第一个参数有关。
实际上,select函数要求通过第一个参数传递监视对象文件描述符的数量。因此,需要得到注册在fd_set变量中的文件描述符数。但每次新建文件描述符时,其值都会增1,故只需将最大的文件描述符值加1再传递到select函数即可。(加1是因为文件描述符的值从0开始)
第二,超时时间与最后一个参数有关
其中timeval结构体如下:

struct timeval
{
    long tv_sec;
    long tv_usec;
};

本来select函数只有在监视文件描述符发生变化时才返回,未发生变化会进入阻塞状态。指定超时时间就是为了防止这种情况发生。
将上述结构体填入时间值,然后将结构体地址值传给select函数的最后一个参数,此时,即使文件描述符中未发生变化,只要过了指定时间,也可以从函数返回。不过这种情况下,select函数返回0。 不想设置超时最后一个参数只需要传递NULL。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux网络编程----UDP编程基础知识 的相关文章

随机推荐

  • Mybatis:Reader entry: ���� 4 乱码问题之解决方法

    问题 xff1a 小编在使用MyBatis进行测试时 xff0c Reader entry xfffd xfffd xfffd xfffd 4 xff0c 这是因为使用Maven xff0c 缺少相应的依赖 xff0c 导入即可 xff1a
  • Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@54227100]之解决方法

    错误 xff1a 使用Mybatis插入数据到Mysql数据库时 xff0c 程序运行没有报错但是数据并没有插入到Mysql数据库中去 xff0c 查看运行结果 xff0c 好像是事务没有提交 xff1a 解决方法 xff1a 使用工厂生产
  • C语言实现任意栈之间的进制转换

    题目 xff1a 利用栈 xff0c 将十进制数字N转换为D进制 xff08 D 61 2 8 16 xff09 xff0c 其中16进制对应的符号是0 9 xff0c A F 要求 xff1a 十进制数字和N进制从键盘输入获得 xff0c
  • 防止C语言头文件被重复包含

    文章目录 方法一 xff1a 使用宏保护防止C语言头文件被重复包含 xff08 很常用 xff09 方法二 xff1a pragma once 在头文件的最开始加入 比较常用 xff09 参考链接 xff1a https blog csdn
  • 栈的应用之括号匹配算法

    算法思路 xff1a 初始化一个栈 xff0c 命名为s 依次遍历待匹配的字符串 如果当前字符为左括号 xff08 即 39 39 39 39 39 39 中的任意一个 xff09 xff0c 则将其入栈 如果当前字符为右括号 xff08
  • jsp页面在浏览器中显示乱码( 没有账号?)

    错误 xff1a jsp页面在浏览器显示乱码 xff0c 如下图所示 xff1a 解决方法 xff1a 主要是因为浏览器使用的编码格式与自己开发文件存储内容的编码不一致导致的 xff0c 所以需要在jsp页面中添加如下代码 xff0c 问题
  • 队列的应用之打印杨辉三角形

    题目 xff1a 利用队列打印杨辉三角形 特点 xff1a 杨辉三角除第一行为两个1以外 xff0c 从第二行开始 xff0c 每一行的首尾都为1 xff0c 中间位置的数为上一行中与之相邻的两个数之和 xff0c 可以使用我们学过的队列问
  • 栈和队列的应用之停车问题

    题目 xff1a 设停车场是一个可停放n辆汽车的狭长通道 xff0c 且只有一个大门可供汽车进出 汽车在停车场内按车辆到达时间的先后顺序 xff0c 依次由北向南排列 xff08 大门在最南端 xff0c 最先到达的第一辆车停放在停车场的最
  • Jupyter Notebook 安装与使用教程

    一 什么是Jupyter Notebook xff1f 1 简介 Jupyter Notebook是基于网页的用于交互计算的应用程序 其可被应用于全过程计算 xff1a 开发 文档编写 运行代码和展示结果 Jupyter Notebook官
  • java.lang.NoSuchMethodError: org.springframework.core.type.AnnotationMetadata.introspect之解决方法

    错误 xff1a idea中使用spring整合mybatis报错 xff1a java lang NoSuchMethodError org springframework core type AnnotationMetadata int
  • 栈和队列的应用之回文数判断

    题目 xff1a 采用栈和队列的方法检测并输出一个单词是否为回文 代码 xff1a include lt stdio h gt include lt malloc h gt define SIZE 20 using namespace st
  • 二叉链表树的遍历

    题目 xff1a 使用二叉链表树创建算法Status CreatBiTree BiTree amp T 和其他代码 二叉树的遍历有三种 xff1a 前序遍历 xff1a 先访问根节点 xff0c 再遍历左子树 xff0c 最后遍历右子树 x
  • opencv的框架与各模块功能介绍

    记录一下自己的所学知识 xff0c 便于日后回顾与整理 文中内容多为摘录 xff0c 具体链接如下 xff1a 摘录自 xff1a https zhuanlan zhihu com p 33008701 xff08 框架介绍 xff09 h
  • Android调用C/C++库

    AndroidStudio版本2021 1 1 一 AndroidStudio将C C 43 43 库打包成so库过程 AndroidStudio新建NativeC 43 43 工程 xff1b 在Tools gt SDK Manager里
  • SocketCan 应用编程

    SocketCan 应用编程 由于 Linux 系统将 CAN 设备作为网络设备进行管理 xff0c 因此在 CAN 总线应用开发方面 xff0c Linux 提供了SocketCAN 应用编程接口 xff0c 使得 CAN 总线通信近似于
  • QT开发笔记(继承 QObject 的线程 )

    继承 QObject 的线程 在第 10 章章节开头已经说过 xff0c 继承 QThread 类是创建线程的一种方法 xff0c 另一种就是继承 QObject 类 继承 QObject 类更加灵活 它通过 QObject moveToT
  • CoppeliaSim:视觉传感器的使用与属性参数

    视觉传感器类型 http www coppeliarobotics com helpFiles index html Orthographic projection type the field of view of orthographi
  • 华为Atlas200DK环境配置指南(版本20.0.0)

    官方参考文档 https support huaweicloud com usermanual A200dk 3000 atlas200dk 02 0024 html 务必保证配置时版本 20 0 0 一致 1 配置开发环境 自己电脑 若不
  • PX4 QGC地面站自定义参数

    QGC地面站自定义参数 xff08 新手操作 xff09 v1 8 2 QGC以往版本下载地址 htps github com mavlink qgroundcontrol tags 最终的添加结果如下 xff1a 具体步骤如下 xff1a
  • Linux网络编程----UDP编程基础知识

    UDP概述 UDP 是 User Datagram Protocol 的简称 xff0c 中文名是用户数据报协议 xff0c 是一个简单的面向数据报的传输层协议 xff0c 在网络中用于处理数据包 xff0c 是一种无连接的协议 UDP 不