UDP sendto和recvfrom使用详解

2024-05-09 14:18

本文主要是介绍UDP sendto和recvfrom使用详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


udp

在网络编程中,UDP运用非常广泛。很多网络协议是基于UDP来实现的,如SNMP等。大家常常用到的局域网文件传输软件飞鸽传书也是基于UDP实现的。

本篇文章跟大家分享linux下UDP的使用和实现,主要介绍下sendto()和recvfrom()两个函数的使用,以及INADDR_ANY的说明,并在最后展示了一个经过自己测试可用的UDP Server和UDP Client的代码示例。

头文件

1 #include <sys/types.h>
2 #include <sys/socket.h>

函数原型

1 int sendto (int s, const void *buf, int len, unsigned int flags, const struct sockaddr *to, int tolen);
2  
3 int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);

 

函数说明

sendto(),是把UDP数据报发给指定地址;recvfrom()是从指定地址接收UDP数据报。

参数说明

  • \s:              socket描述符。
  • \buf:         UDP数据报缓存地址。
  • \len:          UDP数据报长度。
  • \flags:       该参数一般为0。
  • \to:            sendto()函数参数,struct sockaddr_in类型,指明UDP数据发往哪里报。
  • \tolen:      对方地址长度,一般为:sizeof(struct sockaddr_in)。
  • \fromlen:recvfrom()函数参数,struct sockaddr_in类型,指明从哪里接收UDP数据报。

函数返回值

对于sendto()函数,成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。

对于recvfrom()函数,成功则返回接收到的字符数,失败则返回-1,错误原因存于errno中。

struct sockaddr_in结构体

该结构体的定义如下:

01 /* Structure describing an Internet (IP) socket address. */
02 #define __SOCK_SIZE__   16      /* sizeof(struct sockaddr)  */
03 struct sockaddr_in {
04   sa_family_t       sin_family; /* Address family       */
05   __be16        sin_port;   /* Port number          */
06   struct in_addr    sin_addr;   /* Internet address     */
07  
08   /* Pad to size of `struct sockaddr'. */
09   unsigned char     __pad[__SOCK_SIZE__ - sizeof(short int) -
10             sizeof(unsigned short int) - sizeof(struct in_addr)];
11 };

其中,sin_family指明地址族,一般使用AF_INET:

1 #define AF_INET     2   /* Internet IP Protocol     */

sin_port:指明UDP端口;sin_addr指明IP地址:

1 /* Internet address. */
2 struct in_addr {
3     __be32  s_addr;
4 };

INADDR_ANY说明

INADDR_ANY,是个特殊IP地址 ,表示任务的IP地址,作为服务器端的时候经常要用到。对于它的解释,摘用下面一段英文(来自于:http://www.cs.cmu.edu/~srini/15-441/F01.full/www/assignments/P2/htmlsim_split/node18.html):

When you wrote your simple FTP server in project 1, you probably bound your listening socket to the special IP address INADDR_ANY. This allowed your program to work without knowing the IP address of the machine it was running on, or, in the case of a machine with multiple network interfaces, it allowed your server to receive packets destined to any of the interfaces. In reality, the semantics of INADDR_ANY are more complex and involved.

In the simulator, INADDR_ANY has the following semantics: When receiving, a socket bound to this address receives packets from all interfaces. For example, suppose that a host has interfaces 0, 1 and 2. If a UDP socket on this host is bound using INADDR_ANY and udp port 8000, then the socket will receive all packets for port 8000 that arrive on interfaces 0, 1, or 2. If a second socket attempts to Bind to port 8000 on interface 1, the Bind will fail since the first socket already “owns” that port/interface.

When sending, a socket bound with INADDR_ANY binds to the default IP address, which is that of the lowest-numbered interface.

大概的意思就是,作为接收端,当你调用bind()函数绑定IP时使用INADDR_ANY,表明接收来自任意IP、任意网卡的发给指定端口的数据。作为发送端,当用调用bind()函数绑定IP时使用INADDR_ANY,表明使用网卡号最低的网卡进行发送数据,也就是UDP数据广播。

关于UDP数据报

UDP都是以数据报的形式进行发送和接收的,而TCP是以数据流的形式进行发送和接收的。数据报和数据流,这两者要区分开来。

UDP Server和Client源码实例

UDP Server:

01 #include <sys/types.h>
02 #include <sys/socket.h>
03 #include <netinet/in.h>
04 #include <arpa/inet.h>
05 #include <unistd.h>
06 #include <stdlib.h>
07 #include <string.h>
08 #include <stdio.h>
09  
10 #define UDP_TEST_PORT       50001
11  
12 int main(int argC, char* arg[])
13 {
14     struct sockaddr_in addr;
15     int sockfd, len = 0;   
16     int addr_len = sizeof(struct sockaddr_in);
17     char buffer[256];  
18  
19     /* 建立socket,注意必须是SOCK_DGRAM */
20     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
21         perror ("socket");
22         exit(1);
23     }
24  
25     /* 填写sockaddr_in 结构 */
26     bzero(&addr, sizeof(addr));
27     addr.sin_family = AF_INET;
28     addr.sin_port = htons(UDP_TEST_PORT);
29     addr.sin_addr.s_addr = htonl(INADDR_ANY) ;// 接收任意IP发来的数据
30  
31     /* 绑定socket */
32     if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr))<0) {
33         perror("connect");
34         exit(1);
35     }
36  
37     while(1) {
38         bzero(buffer, sizeof(buffer));
39         len = recvfrom(sockfd, buffer, sizeof(buffer), 0,
40                        (struct sockaddr *)&addr ,&addr_len);
41         /* 显示client端的网络地址和收到的字符串消息 */
42         printf("Received a string from client %s, string is: %s\n",
43                 inet_ntoa(addr.sin_addr), buffer);
44         /* 将收到的字符串消息返回给client端 */
45         sendto(sockfd,buffer, len, 0, (struct sockaddr *)&addr, addr_len);
46     }
47  
48     return 0;
49 }
50  
51 // ----------------------------------------------------------------------------
52 // End of udp_server.c

UDP Client:

01 #include <sys/types.h>
02 #include <sys/socket.h>
03 #include <netinet/in.h>
04 #include <arpa/inet.h>
05 #include <unistd.h>
06 #include <stdlib.h>
07 #include <string.h>
08 #include <stdio.h>
09  
10 #define UDP_TEST_PORT       50001
11 #define UDP_SERVER_IP       "127.0.0.1"
12  
13 int main(int argC, char* arg[])
14 {
15     struct sockaddr_in addr;
16     int sockfd, len = 0;   
17     int addr_len = sizeof(struct sockaddr_in);     
18     char buffer[256];
19  
20     /* 建立socket,注意必须是SOCK_DGRAM */
21     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
22         perror("socket");
23         exit(1);
24     }
25  
26     /* 填写sockaddr_in*/
27     bzero(&addr, sizeof(addr));
28     addr.sin_family = AF_INET;
29     addr.sin_port = htons(UDP_TEST_PORT);
30     addr.sin_addr.s_addr = inet_addr(UDP_SERVER_IP);
31  
32     while(1) {
33         bzero(buffer, sizeof(buffer));
34  
35         printf("Please enter a string to send to server: \n");
36  
37         /* 从标准输入设备取得字符串*/
38         len = read(STDIN_FILENO, buffer, sizeof(buffer));
39  
40         /* 将字符串传送给server端*/
41         sendto(sockfd, buffer, len, 0, (struct sockaddr *)&addr, addr_len);
42  
43         /* 接收server端返回的字符串*/
44         len = recvfrom(sockfd, buffer, sizeof(buffer), 0,
45                        (struct sockaddr *)&addr, &addr_len);
46         printf("Receive from server: %s\n", buffer);
47     }
48  
49     return 0;
50 }
51  
52 // ----------------------------------------------------------------------------
53 // End of udp_client.c

上述代码是经过验证可用的。

这篇关于UDP sendto和recvfrom使用详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/973619

相关文章

使用DeepSeek API 结合VSCode提升开发效率

《使用DeepSeekAPI结合VSCode提升开发效率》:本文主要介绍DeepSeekAPI与VisualStudioCode(VSCode)结合使用,以提升软件开发效率,具有一定的参考价值... 目录引言准备工作安装必要的 VSCode 扩展配置 DeepSeek API1. 创建 API 请求文件2.

使用TomCat,service输出台出现乱码的解决

《使用TomCat,service输出台出现乱码的解决》本文介绍了解决Tomcat服务输出台中文乱码问题的两种方法,第一种方法是修改`logging.properties`文件中的`prefix`和`... 目录使用TomCat,service输出台出现乱码问题1解决方案问题2解决方案总结使用TomCat,

解决IDEA使用springBoot创建项目,lombok标注实体类后编译无报错,但是运行时报错问题

《解决IDEA使用springBoot创建项目,lombok标注实体类后编译无报错,但是运行时报错问题》文章详细描述了在使用lombok的@Data注解标注实体类时遇到编译无误但运行时报错的问题,分析... 目录问题分析问题解决方案步骤一步骤二步骤三总结问题使用lombok注解@Data标注实体类,编译时

Java中注解与元数据示例详解

《Java中注解与元数据示例详解》Java注解和元数据是编程中重要的概念,用于描述程序元素的属性和用途,:本文主要介绍Java中注解与元数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参... 目录一、引言二、元数据的概念2.1 定义2.2 作用三、Java 注解的基础3.1 注解的定义3.2 内

Java中使用Java Mail实现邮件服务功能示例

《Java中使用JavaMail实现邮件服务功能示例》:本文主要介绍Java中使用JavaMail实现邮件服务功能的相关资料,文章还提供了一个发送邮件的示例代码,包括创建参数类、邮件类和执行结... 目录前言一、历史背景二编程、pom依赖三、API说明(一)Session (会话)(二)Message编程客

C++中使用vector存储并遍历数据的基本步骤

《C++中使用vector存储并遍历数据的基本步骤》C++标准模板库(STL)提供了多种容器类型,包括顺序容器、关联容器、无序关联容器和容器适配器,每种容器都有其特定的用途和特性,:本文主要介绍C... 目录(1)容器及简要描述‌php顺序容器‌‌关联容器‌‌无序关联容器‌(基于哈希表):‌容器适配器‌:(

JavaScript中的isTrusted属性及其应用场景详解

《JavaScript中的isTrusted属性及其应用场景详解》在现代Web开发中,JavaScript是构建交互式应用的核心语言,随着前端技术的不断发展,开发者需要处理越来越多的复杂场景,例如事件... 目录引言一、问题背景二、isTrusted 属性的来源与作用1. isTrusted 的定义2. 为

使用Python实现高效的端口扫描器

《使用Python实现高效的端口扫描器》在网络安全领域,端口扫描是一项基本而重要的技能,通过端口扫描,可以发现目标主机上开放的服务和端口,这对于安全评估、渗透测试等有着不可忽视的作用,本文将介绍如何使... 目录1. 端口扫描的基本原理2. 使用python实现端口扫描2.1 安装必要的库2.2 编写端口扫

使用Python实现操作mongodb详解

《使用Python实现操作mongodb详解》这篇文章主要为大家详细介绍了使用Python实现操作mongodb的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、示例二、常用指令三、遇到的问题一、示例from pymongo import MongoClientf

SQL Server使用SELECT INTO实现表备份的代码示例

《SQLServer使用SELECTINTO实现表备份的代码示例》在数据库管理过程中,有时我们需要对表进行备份,以防数据丢失或修改错误,在SQLServer中,可以使用SELECTINT... 在数据库管理过程中,有时我们需要对表进行备份,以防数据丢失或修改错误。在 SQL Server 中,可以使用 SE