深入理解Linux下UDP.recvmsg的使用方法 (linux udp recvmsg)

UDP是一种无连接的传输协议,可以直接向目标IP地址和端口发送数据,但是接收数据需要使用recvfrom或者recvmsg函数。其中,recvmsg函数可以获取更多的信息,比如源IP地址和端口号等,这在网络编程中非常有用。本文将深入探讨Linux下UDP.recvmsg函数的使用方法。

1. UDP.recvmsg函数的定义

下面是UDP.recvmsg函数的定义:

“`c

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

“`

其中,

– sockfd:套接字描述符;

– msg:指向msghdr结构体的指针,包含了接收到的数据和其他相关信息;

– flags:控制函数调用的行为。

2. msghdr结构体

在使用UDP.recvmsg函数时,需要定义一个msghdr结构体来保存接收到的数据和相关信息。msghdr结构体的定义如下:

“`c

struct msghdr {

void *msg_name; /* optional address */

socklen_t msg_namelen; /* size of address */

struct iovec *msg_iov; /* scatter/gather array */

size_t msg_iovlen; /* # elements in msg_iov */

void *msg_control; /* ancillary data, see below */

size_t msg_controllen; /* ancillary data buffer len */

int msg_flags; /* flags on received message */

};

“`

其中,

– msg_name:源IP地址和端口号;

– msg_namelen:msg_name缓冲区的长度;

– msg_iov:指向一个或多个iovec结构体的指针,表示一组分散的缓冲区;

– msg_iovlen:msg_iov缓冲区中元素的数量;

– msg_control:与接收到的数据相关的辅助数据;

– msg_controllen:msg_control缓冲区的长度;

– msg_flags:MSG_PEEK等标志。

3. recvmsg函数的使用方法

下面是UDP.recvmsg函数的详细使用方法:

(1)创建套接字

在使用recvmsg函数之前,需要先创建一个UDP套接字。以下是创建套接字的示例代码:

“`c

int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

if (sockfd

perror(“socket() error”);

exit(EXIT_FLURE);

}

“`

在创建套接字时,我们指定了协议簇为IPv4(AF_INET)、套接字类型为UDP(SOCK_DGRAM)以及协议为UDP(IPPROTO_UDP)。这样我们就创建了一个UDP套接字。

(2)设置套接字选项

在接收UDP数据时,我们需要设置SO_REUSEADDR套接字选项来允许多个套接字绑定到同一个端口。以下是设置SO_REUSEADDR选项的示例代码:

“`c

int optval = 1;

if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))

perror(“setsockopt() error”);

exit(EXIT_FLURE);

}

“`

(3)绑定套接字

在接收UDP数据之前,我们需要将套接字绑定到一个端口上。以下是绑定套接字的示例代码:

“`c

struct sockaddr_in server_addr = {0};

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(8888);

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr))

perror(“bind() error”);

exit(EXIT_FLURE);

}

“`

在绑定套接字时,我们指定了端口号为8888,并将IP地址设置为INADDR_ANY,表示绑定到所有可用IP地址上。

(4)接收UDP数据

接下来,我们将详细介绍如何使用UDP.recvmsg函数来接收UDP数据。

我们首先定义一个iovec结构体,用于保存接收到的数据:

“`c

char buf[512] = {0};

struct iovec iov;

iov.iov_base = buf;

iov.iov_len = sizeof(buf);

“`

接着,我们定义一个msghdr结构体,用于保存接收到的数据和相关信息:

“`c

struct msghdr msg = {0};

msg.msg_name = NULL;

msg.msg_namelen = 0;

msg.msg_iov = &iov;

msg.msg_iovlen = 1;

“`

在定义msghdr结构体时,我们将msg_name设置为NULL,表示不获取源IP地址和端口号。如果需要获取源IP地址和端口号,则需要定义一个sockaddr_in结构体,并将它赋给msg_name指针。

然后,我们调用UDP.recvmsg函数来接收UDP数据:

“`c

ssize_t n = recvmsg(sockfd, &msg, 0);

“`

在调用UDP.recvmsg函数时,我们将定义好的msghdr结构体作为参数传入。函数返回的是接收到的数据长度(即缓冲区中的字节数)。

我们可以使用memcmp函数来比较接收到的数据和期望的数据是否相同。以下是完整的接收UDP数据的示例代码:

“`c

char expect[512] = “Hello, world!”;

char buf[512] = {0};

struct iovec iov;

iov.iov_base = buf;

iov.iov_len = sizeof(buf);

struct msghdr msg = {0};

msg.msg_name = NULL;

msg.msg_namelen = 0;

msg.msg_iov = &iov;

msg.msg_iovlen = 1;

ssize_t n = recvmsg(sockfd, &msg, 0);

if (n

perror(“recvmsg() error”);

exit(EXIT_FLURE);

} else if (n == 0) {

printf(“recvmsg() returned 0\n”);

} else {

if (memcmp(buf, expect, strlen(expect)) == 0) {

printf(“Received: %s”, buf);

} else {

printf(“Received unexpected data\n”);

}

}

“`

4.

UDP.recvmsg函数是一个非常有用的函数,可以获取更多的信息,比如源IP地址和端口号等。在网络编程中,我们可以使用UDP.recvmsg函数接收UDP数据并进行相应的处理。本文详细介绍了Linux下UDP.recvmsg函数的使用方法,包括创建套接字、设置套接字选项、绑定套接字、接收UDP数据等步骤。

相关问题拓展阅读:

  • 如何用recvmsg和sendmsg来编写sctp的程序
  • 在Linux 上,编写一个每秒接收 100万UDP数据包的程序究竟有多难

如何用recvmsg和sendmsg来编写sctp的程序

I.

msghdr 与 cmsghdr

struct msghdr {

void *msg_name;

intmsg_namelen;

struct iovec * msg_iov;

unsigned long msg_iovlen;

void *msg_control;

unsigned long msg_controllen;

unsignedmsg_flags;

};

结构成员可以分为下面的四组:

1.

套接口地址成员 msg_name 与吵凳 msg_namelen ; msg_name

指向要发送或接收信息的套接口地址。 msg_namelen 指明了这个套接口地址的长度。

msg_name 在调用 recvmsg 时指向接收地址,在调用 sendmsg 时指向目的地址。

2.

I/O 向量引用 msg_iov 与 msg_iovlen 它是实际的数据缓冲区,这个

msg_iovlen 是 msg_iov 的个数,不是长度。 msg_iov 成员指向一个

struct iovec 数组。

3.

附属数据缓冲区成员 msg_control 与 msg_controllen ,msg_control 指向附属数据缓冲区,而

msg_controllen 指明了缓冲区大小。

4.

接收信息标记位 msg_flags

struct iovec

{

void *iov_base;

unsigned long iov_len;

};

有了这个 iovec ,就可以使用 readv 和 writev 函数在一次函数调用中读取或是写入多个缓冲区,显然比多次 read , write 更有效率。 readv 和 writev 的函数原型如下:

#include

ssize_t writev(int fildes, const struct iovec *iov, int iovcnt);

ssize_t readv(int fildes, const struct iovec *iov, int iovcnt);

struct cmsghdr {

unsigned long cmsg_len; intcmsg_level;

intcmsg_type;

};

·cmsg_len 附属数据的字节数,这包含结构头的尺寸,这个值是由 CMSG_LEN() 宏计算的;

·cmsg_level 表明了原始的协议级绝察别 ( 例如, SOL_SOCKET) ;

·cmsg_type 表明了升宏旅控制信息类型 ( 例如, SCM_RIGHTS ,附属数据对象是文件描述符; SCM_CREDENTIALS ,附属数据对象是一个包含证书信息的结构 )

msghdr 和 cmsghdr: Linux 系统为这些结构提供了一系列的宏来简化我们的工作,这些宏可以在不同的 UNIX 平台之间进行移植:

#include

struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh);

输入参数:指向 struct msghdr 结构的指针; 返回指向附属数据缓冲区内的之一个附属对象的 struct cmsghdr 指针。如果不存在附属数据对象则返回的指针值为 NULL 。

struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh, struct cmsghdr *cmsg);

输入参数:指向 struct msghdr 结构的指针,指向当前 struct cmsghdr 的指针;

这个用于返回下一个附属数据对象的 struct cmsghdr 指针,如果没有下一个附属数据对象,这个宏就会返回 NULL

size_t CMSG_SPACE(size_t length);

输入参数:附属数据缓冲区中的对象大小; 计算 cmsghdr 头结构加上附属数据大小,并包括对其字段和可能的结尾填充字符,注意 CMSG_LEN() 值并不包括可能的结尾填充字符。 CMSG_SPACE() 宏对于确定所需的缓冲区尺寸是十分有用的。 注意如果在缓冲区中有多个附属数据,一定要同时添加多个 CMSG_SPACE() 宏调用来得到所需的总空间。

void *CMSG_DATA(struct cmsghdr *cmsg)

输入参数:指向 cmsghdr 结构的指针 ;

返回跟随在头部以及填充字节之后的附属数据的之一个字节 ( 如果存在 ) 的地址。

size_t CMSG_LEN(size_t length)

输入参数:附属数据缓冲区中的对象大小; 计算 cmsghdr

头结构加上附属数据大小,包括必要的对其字段,这个值用来设置 cmsghdr 对象的 cmsg_len 成员.

int sendmsg(int, const struct msghdr *msg, unsigned int

flags)

int recvmsg(int s, struct msghdr *msg, unsigned int flags)

s, 套接字通道,对于 sendmsg 是发送套接字,对于 recvmsg 则对应于接收套接字;

msg ,信息头结构指针;

flags , 可选的标记位, 这与 send 或是 sendto

函数调用的标记相同。

函数的返回值为实际发送 / 接收的字节数。否则返回 -1 表明发生了错误

sctp

从协议栈的角度看,于tcp,udp同等级别的层次上的。具有tcp和udp不同的优点。从传输的角度看,它可以象tcp那样点对点的那样传输,也可以像udp那样一对多那样传输,但这两种方式对于sctp来说都是建立连接的。下面就介绍这两种方式的编程方式:

UDP那样点对多点的方式(代码片段):

sctpSK = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);

error = sctp_bindx(sctpSK, (struct sockaddr *)&tempSockAddr,

1, SCTP_BINDX_ADD_ADDR);

listen(sctpSK, 1);

typedef union {

struct sctp_initmsg init;

struct sctp_sndrcvinfo sndrcvinfo;

} _sctp_cmsg_data_t;

// buffer and variables used to read data from recvmsg control

messags

char

incmsg;

// data

buffer

struct

iovec iov;

// the

main msghdr structure used to receive/send messages

struct

msghdr inmessage;

struct

sockaddr_in msg_name;

memset(&inmessage, 0, sizeof(inmessage));

iov.iov_base = malloc(SCTP_RX_BUFFER_SIZE);

if

(iov.iov_base == NULL)

{

exit(EXIT_FAILURE);

}

iov.iov_len = SCTP_RX_BUFFER_SIZE;

inmessage.msg_name = &msg_name;

inmessage.msg_namelen = sizeof(msg_name);

inmessage.msg_iov = &iov;

inmessage.msg_iovlen = 1; //

number of iovs in the inmessage

inmessage.msg_control = incmsg;

inmessage.msg_controllen =

sizeof(incmsg);

received = recvmsg(sctpSK, &inmessage, MSG_WAITALL);

解析这个收到到的inmessage相应的代码如下:

union sctp_notification {

struct

{

__u16

sn_type;

__u16 sn_flags;

__u32 sn_length;

}

sn_header;

struct

sctp_assoc_change sn_assoc_change;

struct

sctp_paddr_change sn_paddr_change;

struct

sctp_remote_error sn_remote_error;

struct

sctp_send_failed sn_send_failed;

struct

sctp_shutdown_event sn_shutdown_event;

struct

sctp_adaption_event sn_adaption_event;

struct

sctp_pdapi_event sn_pdapi_event;

在Linux 上,编写一个每秒接收 100万UDP数据包的程序究竟有多难

udp是数据报协议,一次发送只要不超过65535字节(一般为6000字节以下才能发送成功),协议栈就加上udp头一次发送,当然IP层会分片。但接收端肯定是一次收到或者没收到,而不是培毕局分为两数大次或多次收到。你可以用select,epoll这些多路IO就知道,它配让只。

linux udp recvmsg的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux udp recvmsg,深入理解Linux下UDP.recvmsg的使用方法,如何用recvmsg和sendmsg来编写sctp的程序,在Linux 上,编写一个每秒接收 100万UDP数据包的程序究竟有多难的信息别忘了在本站进行查找喔。

香港服务器首选树叶云,2H2G首月10元开通。
树叶云(shuyeidc.com)提供简单好用,价格厚道的香港/美国云服务器和独立服务器。IDC+ISP+ICP资质。ARIN和APNIC会员。成熟技术团队15年行业经验。

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/162898.html<

(0)
运维的头像运维
上一篇2025-03-18 21:53
下一篇 2025-03-18 21:54

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注