linux udp编程_linux中socket编程

linux udp编程_linux中socket编程本文主要描述了linux中UDP编程中的相关细节,涉及到点对点通信,组播,广播等

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

在前面的文件中,我们介绍了linux网络编程中与IP相关的知识和常用的函数总结,本文针对具体的UDP通信,来详细的介绍UDP通信的使用,包括UDP通信中的点对点通信,多播,广播等。

一、UDP通信中服务端和客户端的基本编程框架

与TCP相比较,UDP是面向无连接的通信方式,不需要connect、listen、accept等函数操作,不用维护TCP的连接、断开等状态。具体通信流程如下所示:

linux udp编程_linux中socket编程

上面的通信过程还是比较清晰的,在实际的使用过程中,有几点需要注意下: 

1、我们在编写服务端UDP程序时,bind是一个必须的步骤,这样系统才能知道我们程序recvfrom想从哪里或者哪个端口得到数据,如果没有这个不走,默认是无法收到数据的。当然,在我们服务端创建socket后,主动往外发送一个数据,这样即使我们不进行绑定,我们依然可以收到数据,这只是系统通过我们的发送,自动的绑定了一个端口,这个并不是我们想要的,实际的使用中,也并不推荐这种方式。

2、在上面的通信框架中,客户端并没有使用bind的操作,确实如此,因为客户端一般作为通信的发起者,都是主动往外发送数据,如1中的描述,这个过程由系统聪明的帮我们记录的端口信息,当服务端有数据回复的时候,系统就知道这个数据该转发给哪个端口了。但是,并不是说我们就不能主动的进行bind的操作。

3、关于服务端的bind操作,在存在组播,多播等多种通信方式的情况下,也还有一些需要注意的点,这个我们在下面的章节中描述

二、UDP通信的基本函数说明

在UDP中,完成一个基本的通信涉及到的几个函数如下:

int socket(int domain, int type, int protocol);
int bind(int sockfd, const struct sockaddr *addr,
                socklen_t addrlen);

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

以上几个函数基本能做到 ”看名知意“,但是有一个小细节(也可以说是一个小坑)需要特别的注意:sendto中的addrlen参数很好理解,就是struct sockaddr参数的长度,一般在使用的过程中也不会有什么疑问,但是我们在使用recvfrom时,就需要注意addrlen这个参数了,如果我们不需要关心发送者的IP信息,填NULL就行了

recvfrom(sockfd, buf, len, flags, NULL, NULL);

但是当我们需要知道发送者的IP信息时,就需要指定这两个参数,用来或者发送者的IP信息和IP的数据长度

uint32_t addr_size;
struct sockaddr_in addr
recvfrom(socket, msg, msg_len, 0, (struct sockaddr *)&addr, &addr_size);

粗看上面的代码并没有什么问题,正常的理解就是addr中存在发送者的IP信息,addr_size存放addr数据的长度,但是,在实际使用中,这样调用后,我们打印addr中的信息,确实一个错误的IP信息或者0.0.0.0这样的地址信息,这是什么原因呢,在那个男人的中的描述,有如下的一段话

linux udp编程_linux中socket编程

 总结来说,就是我们必须初始化addr_size的长度,如果设置的长度比addr中的长度短,则会发生截断,获取到的IP信息不对,正确的使用方式为:

uint32_t addr_size = sizeof(struct sockaddr_in);
struct sockaddr_in addr
recvfrom(socket, msg, msg_len, 0, (struct sockaddr *)&addr, &addr_size);

这样我们才能正确的获取到IP信息。

三、UDP中组播的使用

单播和广播是两个极端,要么对一个主机进行通信,要么对整个局域网上的主机进行通信。但是我们在实际的使用中,通常只是某些主机对通信数据感兴趣,而不是整个局域网上的所有主机都需要这个数据,这种情况就需要组播登场了。

3.1、组播中的IP地址

组播的地址是特定的,D类地址用于多播。D类IP地址就是多播IP地址,即224.0.0.0至239.255.255.255之间的IP地址,并被划分为局部连接多播地址、预留多播地址和管理权限多播地址3类:

1、局部多播地址:在224.0.0.0~224.0.0.255之间,这是为路由协议和其他用途保留的地址,路由器并不转发属于此范围的IP包。·

2、预留多播地址:在224.0.1.0~238.255.255.255之间,可用于全球范围(如Internet)或网络协议。

3、管理权限多播地址:在239.0.0.0~239.255.255.255之间,可供组织内部使用,类似于私有IP地址,不能用于Internet,可限制多播范围。

3.2、组播的使用

组播在基本UDP编程框架的基础上,使用setsockopt()函数和getsockopt()函数来实现,需要设置IP层的相关参数(第二个参数为 IPPROTO_IP),其原型如下:

int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

常见组播设置选项如下:

linux udp编程_linux中socket编程

其中:

选项IP_MULTICASE_TTL:设置超时时间,其值optval的设置范围为0-255

选项IP_MULTICAST_IF:设置组播的默认默认网络接口,会从给定的网络接口发送,另一个网络接口会忽略此数据

选项IP_ADD_MEMBERSHIP和IP_DROP_MEMBERSHIP:加入或者退出一个组播组其参数为一个结构体

使用组播的一个基本编程流程如下:

linux udp编程_linux中socket编程

 3.3 使用组播的服务端和客户端例子

(TBD)

三、UDP中广播的使用

UDP广播与普通的UDP通信区别不是很大,如果需要发送广播消息时,只需要在创建完socket后,配置一下套接字,允许进行发送广播消息,上代码

int set_broadcast = 1;
setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &set_broadcast,sizeof(set_broadcast));

四、注意事项

1、在某些情况下,我们的服务端的程序需要同时使用单播、组播和广播的方式,且一般的程序都会使用指定的端口。这样在实际的使用过程中,程序运行经常性的会遇到这样的问题:

Address already in use

例如我们的服务端通过广播的方式在网络上广播了自己的存在,告知其他主机自己的IP地址信息和与自己通信的方式,在广播完成后, 程序会建立一个UDP的单播客户端,等待感兴趣的客户端发送信息。此时,在建立客户端的时候,往往会报上述的错误。

解决方法如下:(允许端口重用)

int on = 1;
ret = setsockopt(udp_net_sta.socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int));
if (ret < 0)
{
    perror("socket set SO_REUSEADDR failed");
}

2、服务端程序,在创建完socket后,有一个bind的操作,对应绑定的端口,没有疑问,但是在选择绑定的IP地址时,一般我们会选择INADDR_ANY,这样不会有什么问题,单播和组播数据都能正常的收到,但是如果我们这边指定了一个固定的IP地址,就只能收到这个IP地址的数据了,如果同样需要实现单播,组播等功能,就需要创建多个socket来实现。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/195954.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • C#中,判断一个字符串是否为数字

    C#中,判断一个字符串是否为数字

  • Mac 计算机的日常使用 和 从零开始搭建Python开发环境

    Mac 计算机的日常使用 和 从零开始搭建Python开发环境Mac计算机的日常使用和从零开始搭建Python开发环境本文作者:魏泯效率魔法师,最后更新时间:2019年1月10日在进行学习mac常用操作的时候,保证你的mac已经连接网络。目录&#

  • 黑群晖安装与使用

    黑群晖安装与使用本教程是一个完整教程,教你0基础0配件安装群晖NAS服务器。

  • 修改表名列名mysql_怎么修改mysql的表名和列名?

    修改表名列名mysql_怎么修改mysql的表名和列名?在mysql中,可以通过“ALTERTABLE旧表名RENAME新表名;”语句来修改表名,通过“ALTERTABLE表名CHANGE旧字段名/列名新字段名/列名新数据类型;”语句来修改列名。修改mysql的表名MySQL通过ALTERTABLE语句来实现表名的修改,语法规则如下:ALTERTABLERENAME[TO];其中,TO为可选参数,使用与否均不影…

  • Java培训机构排名前十_ui培训机构

    Java培训机构排名前十_ui培训机构02JVM线程JVM内存区域JVM运行时内存垃圾回收与算法JAVA四种引用类型GC分代收集算法VS分区收集算法GC垃圾收集器JAVAIO/NIOJVM类加载器03JAVA集合接口继承关系和实现LISTSETMAP04JAVA多线程并发JAVA并发知识库JAVA线程实现/创建方式4种线程池线程生命周期(状态)终止线程4种方式sleep与wait区别start与run区别JAVA后台线程JAVA锁线程基本方法线程上下文切换同步锁与死

  • 显示器屏幕的刷新率hz和帧数fps有什么区别?「建议收藏」

    显示器屏幕的刷新率hz和帧数fps有什么区别?「建议收藏」关于游戏帧数FPS值和屏幕刷新率,相信是电竞玩家比较关心的话题了。如果我们需要了解刷新率和帧数的区别,那么我们就需要知道它们原本是什么意思!下面装机之家科普一下.帧数FPS一般就是我们所说一秒钟内画面刷新的速度,60fps就是一秒钟出现60张画面,而对帧数起到决定性的是电脑中的显卡,显卡性能越强,帧数当然就越高啦,然后画面就越流畅。刷新率一般都是出现在显示器/屏幕上,比如我的是高刷新率显示器,14…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号