前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >linux udp编程_linux中socket编程

linux udp编程_linux中socket编程

作者头像
全栈程序员站长
发布2022-10-04 21:40:56
11K0
发布2022-10-04 21:40:56
举报

大家好,又见面了,我是你们的朋友全栈君。

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

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

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

linux udp编程_linux中socket编程
linux udp编程_linux中socket编程

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

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

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

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

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

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

代码语言:javascript
复制
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就行了

代码语言:javascript
复制
recvfrom(sockfd, buf, len, flags, NULL, NULL);

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

代码语言:javascript
复制
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编程
linux udp编程_linux中socket编程

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

代码语言:javascript
复制
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),其原型如下:

代码语言:javascript
复制
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编程
linux udp编程_linux中socket编程

其中:

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

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

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

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

linux udp编程_linux中socket编程
linux udp编程_linux中socket编程

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

(TBD)

三、UDP中广播的使用

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

代码语言:javascript
复制
int set_broadcast = 1;
setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &set_broadcast,sizeof(set_broadcast));

四、注意事项

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

代码语言:javascript
复制
Address already in use

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

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

代码语言:javascript
复制
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来实现。

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

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022年9月8日 下,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、UDP通信中服务端和客户端的基本编程框架
  • 二、UDP通信的基本函数说明
  • 三、UDP中组播的使用
    • 3.1、组播中的IP地址
      • 3.2、组播的使用
        • 3.3 使用组播的服务端和客户端例子
        • 三、UDP中广播的使用
        • 四、注意事项
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档