Linux下send、sendto、sendmsg函数分析

从网上查到了一些关于这几个函数的使用及注意事项,现终结如下:
功能描述:
发送消息,send只可用于基于连接的套接字,send 和 write唯一的不同点是标志的存在,当标志为0时,send等同于write。sendto 和 sendmsg既可用于无连接的套接字,也可用于基于连接的套接字。除了套接字设置为非阻塞模式,调用将会阻塞直到数据被发送完。

用法:
#include <sys/types.h>
#include <sys/socket.h>

ssize_t send(int sock, const void *buf, size_t len, int flags);
ssize_t sendto(int sock, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
ssize_t sendmsg(int sock, const struct msghdr *msg, int flags);

参数:  
 

sock:索引将要从其发送数据的套接字。
buf:指向将要发送数据的缓冲区。
len:以上缓冲区的长度。
flags:是以下零个或者多个标志的组合体,可通过or操作连在一起

MSG_DONTROUTE:不要使用网关来发送封包,只发送到直接联网的主机。这个标志主要用于诊断或者路由程序。
MSG_DONTWAIT:操作不会被阻塞。
MSG_EOR:终止一个记录。
MSG_MORE:调用者有更多的数据需要发送。
MSG_NOSIGNAL:当另一端终止连接时,请求在基于流的错误套接字上不要发送SIGPIPE信号。
MSG_OOB:发送out-of-band数据(需要优先处理的数据),同时现行协议必须支持此种操作。

to:指向存放接收端地址的区域,可以为NULL。
tolen:以上内存区的长度,可以为0。
msg:指向存放发送消息头的内存缓冲,结构形态如下

struct msghdr {
    void         *msg_name;     


 

    socklen_t     msg_namelen;   
    struct iovec *msg_iov;       
    size_t        msg_iovlen;    
    void         *msg_control;   
    socklen_t     msg_controllen;
    int           msg_flags;     
};


可能用到的数据结构有

struct cmsghdr {
    socklen_t cmsg_len;    
    int       cmsg_level;  
    int       cmsg_type;   
   
};
返回说明:  
成功执行时,返回已发送的字节数。失败返回-1,errno被设为以下的某个值  
EACCES:对于Unix域套接字,不允许对目标套接字文件进行写,或者路径前驱的一个目录节点不可搜索
EAGAIN,EWOULDBLOCK: 套接字已标记为非阻塞,而发送操作被阻塞
EBADF:sock不是有效的描述词
ECONNRESET:连接被用户重置
EDESTADDRREQ:套接字不处于连接模式,没有指定对端地址
EFAULT:内存空间访问出错
EINTR:操作被信号中断
EINVAL:参数无效
EISCONN:基于连接的套接字已被连接上,同时指定接收对象
EMSGSIZE:消息太大
ENOMEM:内存不足
ENOTCONN:套接字尚未连接,目标没有给出
ENOTSOCK:sock索引的不是套接字
EPIPE:本地连接已关闭

#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
void Recv()
{
   struct sockaddr_in serv_addr;
   int sock_fd;
   char line[15] = "Hello world!";
   int size = 13;
   serv_addr.sin_family = AF_INET;
   serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
   serv_addr.sin_port = htons(5000);
   sock_fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
   connect(sock_fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
   send(sock_fd, line, size, 0);
   close(sock_fd);
}


#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
void Sendto()
{
   sockaddr_in receiver_addr;
   int sock_fd;
   char line[15] = "Hello World!";
   sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
   receiver_addr.sin_family = AF_INET;
   receiver_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
   receiver_addr.sin_port = htons(5000);
   sendto(sock_fd, line, 13, 0,(struct sockaddr*)&receiver_addr,sizeof(receiver_addr));
   close(sock_fd);
}


#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
void sendmsg()
{
   struct sockaddr_in receiver_addr;
   int sock_fd;
   char line[15] = "Hello World!";
   struct msghdr msg;
   struct iovec iov;
   sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
 
   receiver_addr.sin_family = AF_INET;
   receiver_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
   receiver_addr.sin_port = htons(5000);
   msg.msg_name = &receiver_addr;
   msg.msg_namelen = sizeof(receiver_addr);
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
   msg.msg_iov->iov_base = line;
   msg.msg_iov->iov_len = 13;
   msg.msg_control = 0;
   msg.msg_controllen = 0;
   msg.msg_flags = 0;
   sendmsg(sock_fd,&msg,0);
   close(sock_fd);
}


<think>嗯,用户的问题是想查找Linux系统中send函数所属的库。根据用户描述,重点在“send函数”和“所属库”这两个关键点上。用户明确排除了文件操作相关的内容,特别标注是网络编程领域的查询。首先需要明确Linux系统调用的层级关系:用户空间的库函数(如glibc)实际上是对内核系统调用的封装。从引用[3]和[4]提供的函数声明可见,send函数属于<sys/socket.h>头文件定义的接口,这是关键线索。考虑到glibc作为Linux标准C库的核心地位,几乎所有系统调用都需要通过它实现用户态与内核的交互。引用[1][3][4][5]反复提到的send函数使用场景都指向socket编程,而socketAPI正是由glibc提供的标准接口。需要澄清的是,虽然glibc实现了send,真正的系统调用编号和参数转换发生在底层。不过用户通常不需要接触这个层面。这个细节是否需要在回答中说明?应该保留技术准确性但避免过度复杂化。关于编译链接的补充很必要,因为用户可能涉及实际开发。根据引用[2]提到的网络编程函数,必须强调需要链接套接字库(-lsocket)的传统做法在现代Linux已经不再需要,glibc已集成此功能。最后要注意用户引用材料中有两个潜在混淆点:1)引用[3]提到recvmsg/sendmsg更通用但非用户所问2)引用[5]的示例可能让用户误以为需要额外转换。在回答中应该主动规避这些无关信息,专注解决“所属库”的核心问题。</think> 根据引用内容分析Linux 中的 `send` 函数属于标准 C 库(glibc)中的**网络编程接口**,具体归属于 **socket API 库**。以下是关键说明: 1. **所属头文件与库** - **声明位置**:`<sys/socket.h>`(引用[3][4]) - **实现库**:`glibc`(GNU C Library) - **依赖关系**:`send` 是套接字操作的核心函数,需链接标准 C 库(编译时通常自动链接,无需额外参数) 2. **功能定位** 作为系统级网络 I/O 函数(引用[1][3]),`send` 通过操作系统内核实现**面向连接的数据传输**(如 TCP 套接字),属于 `socket API` 的一部分(引用[2])。 3. **与其他函数的关系** - 同级函数:`recv`, `sendto`, `recvfrom`, `sendmsg` 等(引用[3][4]) - 底层依赖:最终通过 Linux 内核的 `socket` 子系统实现(引用[4][5]) 4. **使用注意事项** - 需先建立连接(如 TCP 的 `connect`/`accept`) - 数据需处理端序转换(如 `htonl`,引用[5]) - 阻塞行为受 `flags` 参数控制(引用[4][5]) > **编译示例** > 使用 `send` 时只需包含头文件并链接 `glibc`(默认已链接): > ```c > #include <sys/socket.h> // 函数声明 > #include <unistd.h> // 部分辅助函数 > > // 编译命令(gcc): > // gcc program.c -o output -lc // -lc 通常可省略 > ``` --- ### 相关问题 1. `send` 和 `write` 函数在网络编程中有什么区别? 2. 如何通过 `flags` 参数实现 `send` 函数的非阻塞发送? 3. 在 UDP 协议中使用 `send` 函数需要满足哪些条件? > 引用说明: > - `send` 函数声明及参数说明基于套接字 API 实现 [^3][^4] > - 数据发送需端序转换的实践案例 [^5] > - Linux 网络编程核心库为 glibc 和 socket API [^2][^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值