UDP 理解

article/2025/9/21 1:28:00

这里需要指出的一点是,伪首部完全是虚拟的,它并不会和用户数据报一起被发送出去,只是在校验和的计算过程中会被使用到,伪首部主要来自于运载UDP报文的IP数据报首部,将源IP地址和目的IP地址加入到校验和的计算中可以验证用户数据报是否已经到达正确的终点。

所以udp头部大小为8字节

tcp和udp可以同用一个端口。使用地址复用SO_REUSEADDR即可。

udp通用函数

// 接收缓冲区,udp有接收缓冲区,无发送缓冲区

int nRecvBuf=32*1024;//设置为32K

setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));

//发送缓冲区

int nSendBuf=32*1024;//设置为32K

setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));

//地址复用

BOOL bReuseaddr = TRUE;

setsockopt( s, SOL_SOCKET, SO_REUSEADDR, ( const char* )&bReuseaddr, sizeof( BOOL ) );

接收端

1.创建,socket()函数

2.绑定, bind()函数

3.接收 recvfrom

不用实际读取就能检测到数据的到来,可以调用MSG_PEEK标志的recv活recvfrom,或者调用ioctlsocket或select.

ssize_t recvfrom(int sockfd,void *buf,size_t len,unsigned int flags, struct sockaddr *from,socket_t *fromlen);

sockfd:标识一个已连接套接字的描述字。

buf:接收数据缓冲区。

len:缓冲区长度。

flags:调用操作方式。一般为0, 是一个或者多个标志的组合体,可通过“ | ”操作符连在一起:

from:指针,指向装有源地址的缓冲区。可选,如不关心,则为null

fromlen:指针,指向from缓冲区长度值。可选,如不关心,则为null

返回值

如果正确接收返回接收到的字节数,失败返回-1.返回0也是可行的。tcp的read返回0表示对端已关闭,而udp不是。

udp和tcp都有接收缓冲区,在没有收到数据时,默认是阻塞的,可通过设置超时返回(如select机制,默认最大描述符为1024)

延伸connect

1.没有3路握手,只是检查是否存在立即可知的错误(如网络不可达,但如果是网络可达,但应用程序没启动检查不到的,只有调sendto才返回)

2.如果udp调用connect后,不能使用sendto(或者不能在sendto制定目的地址)

3.如果udp调用connect后,只能接受connect所指定地址的数据报,不能接受别的套接字的数据。

相当于不能进行广播和组播了

4.好处:就是只显性连接一次,可以多次发送数据。传输效率更高。

不然调用sendto就是连接一次,发送一次,断开连接一次。再连接,发送,断开连接

5.多次调用connect,可以指定新的目的地址和端口和断开套接字

关闭closesocket() :

只是将socket的资源归还给协议栈。

发送端:

1.创建,socket()函数

2.发送 sendto ()函数:

适合在从同一个socket向不同的远程主机发送数据。

或还有一种办法是,调用connect()函数,再调用send()函数。适用于向同一个远程地址发送数据。

int sendto ( socket s , const void * msg, int len, unsigned int flags, const struct sockaddr * to , int tolen ) ;

send 和 sendto 函数在 UDP 层没有输出缓冲区,因此sendto不会阻塞。而是直接返回。

s 套接字

buff 待发送数据的缓冲区

size 缓冲区长度

Flags 调用方式标志位, 一般为0, 改变Flags,将会改变Sendto发送的形式

addr (可选)指针,指向目的套接字的地址

len addr所指地址的长度

成功则返回实际传送出去的字符数,失败返回-1,返回是0也是可以的。

udp并没有真正的发送缓冲区,和tcp还是有区别的。

对客户端的udp而言,进程首次调用sendto时,绑定一个临时端口,不能在修改了。而ip地址可以随客户发送的udp数据报而变动。

udp sendto输出操作成功返回仅仅表示在接口输出队列中具有存放所形成ip数据报的空间。

说明了udp套接字:由它引发的异步错误并不返回给它,除非它也连接(即如调用了connect函数)。这也是udp使用connect的初衷。

主要区别在于:udp获取目标ip地址的方法是recvmsg函数。

在客户端udp中,调用connect并没有和tcp的三路握手,只能是内核检查存放立即可知的错误,记录对端的ip地址和端口,然后立即返回到进程。如果使用了connect函数,就只能使用read(recv)替代recvfrom ,write(send)替代sendto.

udp可以多次调用connect,其目的是指定新的ip地址和端口,或断开套接字。tcp只能一次调用connect。

调用connect并不给服务器发送任何信息,只是保存对端的ip地址和端口号。

tcp和udp可以同用一个端口。

对于已连接的udp套接字可以调用sendto,但不能指定目的地址。

对于已连接的udp套接字只能通过connect断开连接,而不能通过shutdown.

3.关闭closesocket

主要在udp中,可以扩展,从单播到组播,或广播。可以在同一应用程序同时接收和发送。

udp套接字显性地绑定一个本地ip接口,并发送数据。出现什么情况

udp套接字不会真正和网络接口绑定在一起,而是建立一种关联,即被绑定的ip接口地址成为发出去的udp数据报的源ip地址。

一个数据报即udp只要一打开就处于可写的状态,一经命名就处于可读的状态。

所以,应用程序下socket()调用后,马上可以发送数据。

在调用bind()显式命名或调用sendto函数隐式命名后,马上就可以接收数据。

对于udp多播,发送应用进程的套接字可以不必加入到多播组。

udp广播

一直都UDP层(通过端口号),才能确定是否要丢弃广播数据。

发送端:

1.创建udp套接字,无须绑定端口和地址。

2.设置udp套接字的广播标志。

int flag = 1;

setsockopt(server_sockfd , SOL_SOCKET , SO_BROADCAST , &flag , sizeof(flag) );

3.调用sendto函数,参数中需要明确广播地址和端口号。

#define BROADCAST_IP "192.168.1.255"
#define CLIENT_PORT 9000bzero(&clientaddr , sizeof(clientaddr));
clientaddr.sin_family = AF_INET;
inet_pton(AF_INET , BROADCAST_IP , &clientaddr.sin_addr.s_addr);clientaddr.sin_port = htons(CLIENT_PORT); 
sendto(server_sockfd , buf , strlen(buf) , 0 , (struct sockaddr *)&clientaddr , sizeof(clientaddr));

接收端:

  1. 创建udp套接字,必须绑定端口(该端口是发送端发送的端口)。绑定的IP不可以使用“127.0.0.1”,可以使用真实IP地址或者INADDR_ANY。否则接收失败。

 bzero(&localaddr , sizeof(localaddr));localaddr.sin_family = AF_INET;
inet_pton(AF_INET , "0.0.0.0" , &localaddr.sin_addr.s_addr);localaddr.sin_port = htons(CLIENT_PORT);int ret = bind(confd , (struct sockaddr *)&localaddr , sizeof(localaddr));

2.接收方的Socket不需要设置成广播属性。

3.调用recvfrom函数进行接收.

len = recvfrom(confd , buf , sizeof(buf),0 ,(struct sockaddr*)&from,(socklen_t*)&len);

//from为发送端的本地地址。

相关的广播知识点:

BOOL bBroadcast=TRUE;

setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL));

特点:

1.广播的数据在子网的所有主机都接收。直到传输层才决定是否丢弃。

2.不能够跨越不同的网络,被路由器所隔离开,即只能在局域网,不能应用到广域网

3.接收端的端口号要与广播端绑定的端口号一样。

udp组播

组播在网卡处就对接收地址进行判断,从而丢弃数据包。

一个ip地址可以加入到多个组播组。

1.地址范围:D类IP地址。范围:224.0.0.0~239.255.255.255

2.组播组:永久/临时。永久组播组一般由官方分配。

3.224.0.0.0~224.0.0.255为预留的组播地址,即永久组地址。地址224.0.0.0保留不做分配,其它地址供路由协议使用。

4.224.0.1.0~224.0.1.255是公用组播地址,可以用于Internet。

5.224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效。

6.239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效。

发送端:

1.创建udp套接字,无须绑定端口和地址。

2.调用sendto函数,参数中需要明确组播地址和端口号。

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>int main()
{int server = 0;struct sockaddr_in saddr = {0};int client = 0;struct sockaddr_in remote = {0};socklen_t asize = 0;int len = 0;char buf[32] = "Software";int r = 0;//int brd = 1;server = socket(PF_INET, SOCK_DGRAM, 0);if( server == -1 ){printf("server socket error\n");return -1;}saddr.sin_family = AF_INET;saddr.sin_addr.s_addr = htonl(INADDR_ANY); // 本机地址saddr.sin_port = htons(8888);if( bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1 ){printf("udp server bind error\n");return -1;}printf("udp server start success\n");remote.sin_family = AF_INET;remote.sin_addr.s_addr = inet_addr("224.1.1.168"); //设置一个多播地址remote.sin_port = htons(9000);while( 1 ){len = sizeof(remote);r = strlen(buf);sendto(server, buf, r, 0, (struct sockaddr*)&remote, len);sleep(1);}close(server);return 0;
}

接收端:

1.创建套接字,必须绑定端口(该端口是发送端发送的端口)。绑定的IP不可以使用“127.0.0.1”,可以使用真实IP地址或者INADDR_ANY。否则接收失败。

2.把当前本地的ip地址加人到组播地址。

3.调用recvfrom获取数据,参数为发送端的本地地址。

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>int main()
{int sock = 0;struct sockaddr_in addr = {0};struct sockaddr_in remote = {0};int len = 0;char buf[128] = {0};char input[32] = {0};int r = 0;//多播struct ip_mreq group={0};sock = socket(PF_INET, SOCK_DGRAM, 0);if( sock == -1 ){printf("socket error\n");return -1;}addr.sin_family = AF_INET;addr.sin_addr.s_addr = htonl(INADDR_ANY);addr.sin_port = htons(9000);if( bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1 ){printf("udp bind error\n");return -1;}//remote.sin_family = AF_INET;//remote.sin_addr.s_addr = inet_addr("127.0.0.1");//remote.sin_port = htons(8888);group.imr_multiaddr.s_addr=inet_addr("224.1.1.168");group.imr_interface.s_addr=htonl(INADDR_ANY); //local host//这里INADDR_ANY 为0.0.0.0 通过看ipconfig/ifconfig 可以看到有多个//网络ip地址,这个时候让操作系统选择哪一个端口进行多播数据收发。//在实际的工程中需要明确指定需要哪一个网络地址进行多播数据收发,//不能完全依赖操作系统,否者有时候能够收到数据,有时候收不到数据。setsockopt(sock,IPPROTO_IP,IP_ADD_MEMBERSHIP,&group,sizeof(group));while( 1 ){len=sizeof(remote);r = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr*)&remote, &len);if( r > 0 ){buf[r] = 0;printf("Receive: %s\n", buf);}else{break;}}close(sock);return 0;
}

多播(组播)相关知识点:

ip多播:采用的是“无根”的通讯方式,组内的成员可以相互之间发送和接收数据。IPv4 多播是一个D类的IP地址,范围:224.0.0.0 ----239.255.255.255 之间。

如果多播需要在多个网络断传输,需要考虑使用IGMP协议,该协议运行在主机和组播路由器之间。此外一个套接字注意TTL的值,其作用主要显示数据能传输多远。

1.多播服务端针对特定多播地址只发送一次数据,但是组内的所有客户端都能收到数据

也就是说如果自身不想接受数据,就不要把自己加入到组播地址去。

2.加入特定的多播组即可接收发往该多播组的数据。如果自己想接收数据,就把自己加入组播地址

3.与单播一样,多播是允许在广域网即Internet上进行传输的,而广播仅仅在同一局域网上才能进行;即可以跨网段,跨路由器.所以多播时,路由器能够复制数据并进行转发

常用函数

IPPROTO_IP

当接收者加入到一个多播组以后,再向这个多播组发送数据,这个字段的设置是否允许再返回到本身。

int loop=1; //1:on 0:off

setsockopt(sock,IPPROTO_IP,IP_MULTICAST_LOOP,&loop,sizeof(loop));

IP_MULTICAST_TTL

默认情况下,多播报文的TTL被设置成了1,也就是说到这个报文在网络传送的时候,它只能在自己所在的网络传送,当要向外发送的时候,路由器把TTL减1以后变成了0,这个报文就已经被Discard了。

IP_MULTICAST_IF设置多播接口地址

struct in_addr addr;

setsockopt(s,IPPROTO_IP,IP_MULTICAST_IF,&addr,sizeof(addr))

IP_ADD_MEMBERSHIP 加入一个组播组

struct ip_mreq ipmr;

ipmr.imr_interface.s_addr = inet_addr("192.168.101.1");

ipmr.imr_multiaddr.s_addr = inet_addr("234.5.6.7");

setsockopt(s, IPPROTO_IP, IP_ADDR_MEMBERSHIP, (char*)&ipmr, sizeof(ipmr));

IP_DROP_MEMBERSHIP 离开一个多播组


http://chatgpt.dhexx.cn/article/aGcFrq13.shtml

相关文章

关于TCP/UDP

目录 1、TCP协议 1.1 TCP协议格式 1.2 TCP协议原理 2、UDP协议 在学习TCP/UDP之前先来了解以下整体的通信传输&#xff0c;它是一个向下封装、向上分用的过程&#xff1a; 这是TCP/IP四层模型&#xff0c;所以要想实现通讯&#xff0c;通过TCP建立和断开连接是至关重要的&a…

UDP详解

1、UDP数据包格式 UDP 是User Datagram Protocol的简称&#xff0c; 中文名是用户数据报协议&#xff0c;是OSI&#xff08;Open System Interconnection&#xff0c;开放式系统互联&#xff09; 参考模型中一种无连接的传输层协议&#xff0c;提供面向事务的简单不可靠信息传…

TCPUDP相关介绍

TCP and UDP TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是面向连接的协议&#xff0c;也就是说&#xff0c;在收发数据前&#xff0c;必须和对方建立可靠的连接。 一个TCP连接必须要经过三次握手才能建立起来。断开连接需要四次挥手才…

TCPUDP

TCP&#xff1a;面向连接的服务&#xff0c;可靠的进程到进程的通信协议。&#xff08;因为TCP里面封装了端口号&#xff0c;端口号就意味着一个服务&#xff0c;进程&#xff09;&#xff1b;应用场景&#xff1a;如&#xff1a;文件传输&#xff1b;HTTP应用层协议 UDP&…

TCP/UDP

Tcp / ip : 应用层、传输层、网络层、网络接口层 查看本机ip&#xff1a; windons r &#xff08;进入交互换环境&#xff09;ipconfigping 本机ip 查看本机网络有无问题 端口&#xff1a; 知名端口(固定端口)&#xff1a;0—1023动态端口&#xff1a;程序可以设置的端口 1…

UDP协议的详细解析

UDP数据报 一、UDP的概述&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09; UDP是传输层的协议&#xff0c;功能即为在IP的数据报服务之上增加了最基本的服务&#xff1a;复用和分用以及差错检测。 UDP提供不可靠服务&#xff0c;具有TCP所没有的优…

UDP协议详解

一、UDP协议概述 传输层另一个重要的协议就是用户数据报协议 UDP。UDP 只在 IP 的数据报服务之上增加了很少一点的功能&#xff0c;这就是复用和分用的功能以及差错检测的功能。 <注> UDP(User Datagram Protocol&#xff0c;用户数据报协议) UDP的主要特点是&#xff1a…

截图文字识别工具

tkinter程序源码&#xff1a;初识Python&#xff0c;如有不足请多指教。 import tkinter as tk import keyboard # 安装&#xff1a; pip install keyboard from PIL import ImageGrab # pip install pillow import time from aip import AipOcr # pip install baidu-a…

电脑截图如何快速识别文字?3分钟教会你快速截图识别怎么做

电脑截图已经成为我们日常生活中的常见操作&#xff0c;无论是工作还是学习&#xff0c;我们都有可能需要截取电脑屏幕上的某个区域进行保存或分享。但是&#xff0c;有时候我们需要识别截图中的文字内容&#xff0c;这时候该怎么办呢&#xff1f;接下来&#xff0c;本文将为大…

python截图识别文字_10几行代码,用python打造实时截图识别OCR|python基础教程|python入门|python教程...

https://www.xin3721.com/eschool/pythonxin3721/ 你一定用过那种“OCR神器”&#xff0c;可以把图片中的文字提取出来&#xff0c;极大的提高工作效率。 &#xff01; 今天&#xff0c;我们就来做一款实时截图识别的小工具。顾名思义&#xff0c;运行程序时&#xff0c;可以…

chrome拓展 --截屏文字识别

文章目录 场景源代码功能实现点击在页面上出现裁剪框百度云文字识别复制选中 参考 场景 因为学习通题目都加密了复制过来也无法进行搜题 无奈写了这个插件 为什么使用插件的形式 而不是脚本 &#xff1f; 使用了html2canvas结果是比的是dom文字变成了加密过的 无法识别 于是使用…

微信怎么识别图片文字?其实操作很简单

微信作为中国最流行的社交媒体应用程序之一&#xff0c;已经成为人们分享照片和信息的主要平台之一。在微信中&#xff0c;用户可以轻松地将照片上传到朋友圈或与朋友共享。然而&#xff0c;在某些情况下&#xff0c;这些照片上可能有一些重要的文字信息&#xff0c;这些信息需…

电脑截图怎么识别文字?识别原理又是什么?

在日常工作和生活中&#xff0c;我们经常需要从图片或截图中提取文字&#xff0c;但是手动输入费时费力&#xff0c;因此电脑截图文字识别技术应运而生。本文将介绍电脑截图文字识别的原理和方法。 OCR技术的原理 OCR是一种光学字符识别技术&#xff0c;其原理是将图片中的文字…

C# 通用OCR识别 文字识别 中文识别

软件说明 基于以下两个开源项目&#xff0c;做了再次封装 https://github.com/paddlepaddle/PaddleOCR PaddleOCRSharp: 本项目是一个基于PaddleOCR的C代码修改并封装的.NET的OCR工具类库。包含文本识别、文本检测、基于文本检测结果的统计分析的表格识别功能&#xff0c;同…

手把手教截图识别文字

点击上方 毛利学python&#xff0c;选择置顶或星标 第一时间送达Python 技术干货&#xff01; 最近不想打字&#xff0c;直接截图然后识别出来文字&#xff0c;不就可以不用打吗&#xff1f;我就是太懒了。 keyboard 这个库让你可以控制和监控输入设备。 对于每一种输入设备&a…

屏幕可以截图识别文字?我来教你

我们经常浏览一些网页的时候&#xff0c;看到一些优美的文字&#xff0c;想将它复制下来&#xff0c;却发现粘贴的时候都是一些乱码之类的&#xff0c;以前我估计你们大多数的人都会选择用手抄&#xff0c;但是今天我来了&#xff0c;我给大家介绍一个非常有用的一个方法&#…

python截图识别文字_Python技术:截图文字识别工具

#01 截图文字识别工具 有时候在海报上面&#xff0c;图片上面&#xff0c;或者PDF文档中&#xff0c;经常出现一些唯美的文字。这个时候想要复制下来才发现不能复制。因为有的是图片&#xff0c;有的是PDF。 可以使用Python制作一个小工具&#xff0c;来识别图片上的文字。但…

这几个截图文字识别软件可以自动识别文字

从事新媒体行业的朋友&#xff0c;是不是经常在电脑桌面上或者在浏览也中临时截图识别文字呢&#xff1f;尤其是为了方便&#xff0c;直接识别图片转为文字的话&#xff0c;我们就可以节省了很多打字的时间。那你们知道怎么截图文字识别吗&#xff1f;今天我来教你们3个非常简单…

图片截图识别文字怎么操作?这两个方法不要错过

现如今&#xff0c;图片截图识别文字是一项非常有用的技术。很多小伙伴平时在工作或者生活中都会保存很多图片格式的资料文件把。如果遇到需要讲内容图区到文档中编辑的话&#xff0c;识别技术就可以帮助我们快速识别图片中的文字&#xff0c;从而节省大量的时间。那么图片截图…

python截屏图片识别点击,用python实现截屏识别其中的文字

大家好,欢迎来到 Crossin的编程教室 ! 你一定用过那种“OCR神器”,可以把图片中的文字提取出来,极大的提高工作效率。 今天,我们就来做一款实时截图识别的小工具。顾名思义,运行程序时,可以实时的把你截出来的图片中的文字识别出来。 下次,当你想要复制“百度文库”中的…