Linux Socket发送/接受类函数

write函数和read函数

#include <unistd.h>
/*
* fd : 文件描述符;
* buf : 写入/读取需要用到的数据缓冲区;
* count : 缓冲区的长度;
* return : 成功返回读取/写入的字节数,失败返回-1,设置错误码;
* 
* read/write函数(属于POSIX,不属于ANSI C)是linux下不带缓存的文件IO操作函数之一,所谓的不带缓存
* 是指一个函数只调用系统中的一个函数,本身不带缓冲区;
* 常用于:文本文件;
*/
ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);

writev函数和readv函数

#include <sys/uio.h>
/*
* linux下的两个系统调用,其特点是:
* 在一次执行过程中可以原子的作用于多个缓冲区,这些缓冲区可以是不连续的地址;
*
* fd : 文件描述符;
* iov : 缓冲区数组;
* iovcnt : 缓冲区的个数;
* return : 成功返回读取/写入的字节数,失败返回-1,设置错误码;
*/
//依次将数据读取到iov[0]、iov[1]、iov[2]...中,readv总是先填满前面一个缓冲区,再填下一个
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
//依次将iov数组中各个缓冲区的内容汇集后写到套接字fd中
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
struct iovec {
    void  *iov_base;    /* 缓冲区开始的地址 */
    size_t iov_len;     /* 缓冲区的长度 */
};

send函数和recv函数

/*
* fd : 文件描述符;
* buff : 读取/写入数据的缓冲区;
* nbytes : 缓冲区的长度;
* flag : 函数标志,一般设置为0,其他设置见下表;
* return : 成功返回读取/写入的字节数,失败返回-1,设置错误码;
* 
* 常用于:TCP;
*/
#include <sys/socket.h>

/*
* 接受数据的步骤:
* (1)等待套接字讲发送缓冲区的数据发送完,若等待期间发生网络错误,返回-1;
* (2)等待套接字的接收缓冲区接收数据,协议接收完数据,recv将数据copy到buf中,成功返回本次
* copy字节数,失败则返回-1;
* (3)若接收缓冲区的数据长度大于buf的长度,这种情况需要多次调用recv,直到将接收缓冲区的
* 数据copy完;
* (4)在等待协议接收数据时出现错误,recv视情况返回,若是网络中断,返回0,若是其他错误,返回-1
* (5)recv的主要任务是copy接收缓冲区的内容到buff中,真正做接收的是协议
*/
ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags);
/*
* 发送数据的步骤:
* (1)比较nbytes和套接字缓冲区的长度,若nbytes>缓冲区长度,则直接返回-1,设置错误码
* (2)确定套接字缓冲区的状态,若正在发送,等待;若发送完毕或还没开始发送,比较缓冲区
* 剩余空间和nbytes的大小;
* (3)bytes>剩余缓冲区大小,等待套接字将缓冲区数据发送完;bytes<剩余缓冲区大小,将
* buff中的数据copy到缓冲区;
* (4)copy成功返回本次发送的字节数,若copy失败,返回-1;若等待协议发送数据过程中(copy前)
* 网络连接中断,返回-1;
* (5)数据发送是协议的任务,send只是将数据copy到缓冲区中,若后续协议发送数据失败,
* 则下一次调用socket相关函数直接返回-1;
*/
ssize_t send(int sockfd, const void *buff, size_t nbytes, int flags);

flags参数设置(只列举了部分,各个函数的具体标志值需自行查找):

flags说明适用对象
MSG_DONTROUTE绕过路由表查找send
MSG_DONTWAIT仅本地操作非阻塞send/recv
MSG_OOB发送或接收带外数据send/recv
MSG_PEEK窥看外来消息recv
MSG_WAITALL等待所有数据recv

sendto函数和recvfrom函数

 #include <sys/types.h>
 #include <sys/socket.h>
/*
* sockfd : 接收/发送的文件描述符;
* buf : 接收/发送数据的缓冲区;
* len : 缓冲区的长度;
* flags : 函数标志,一般设置为0,类似send/recv函数;
* src_addr/dest_addr : src_addr指明发送方的地址,dest_addr指明接收方的地址;
* addrlen : 地址结构体的长度;
* return : 成功返回读取/写入的字节数,失败返回-1,设置错误码;
* 
* recvfrom/sendto常用于面向无连接的数据报形式,此时需要设置addr和addr_len的参数;当然也可以
* 用于面向连接的套接字,此时无需设置add和addr_len的参数;
* recvfrom是阻塞函数;sendto在udp层没有发送缓冲区(这里指内核发送缓冲区,但是在内核层有一个
* 数据报最大值限制),发送数据不会阻塞,其他情况下sendto可能会造成阻塞;
* 常用于:UDP;
*/

//若是面向无连接:

/*
* 如果没有设置src_addr(即src_addr内容为空,是一个输出参数)和addr_len(调用前,需要调用者
* 初始化为src_addr大小,调用后,如果结果的src_addr大于初始addr_len值,则会被截断后填充到输出
* 参数src_addr中,此时addr_len的值会被更改为结果src_addr的大小),此时接收数据后会将src_addr设置
* 为对端的地址(常用于UDP服务端,一般会将sockfd绑定本地特定端口);
* 如果设置src_addr(即addr内容不为空,是一个输入参数)和addr_len,可以来确定需要接收那个地址的数据
*(常用于UDP客户端);
*/
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);
//dest_addr和addrlen的地址都必须设置,需要确定发送数据到那个地址
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                 const struct sockaddr *dest_addr, socklen_t addrlen);

sendmsg函数和recvmsg函数

#include <sys/types.h>
#include <sys/socket.h>
/*
* sockfd : 接收/发送的文件描述符;
* msg : 用来设置地址和发送/接收数据缓冲区以及其他控制条件;
* flags : 函数标志,一般设置为0,类似send/recv函数,需要注意的是:flags和msg.msg_flags
* 是相同的,但是在sendmsg中,它会直接引用flags,只是设置msg.msg_flags是不起作用的,
* 在recvmsg中会将flags复制到msg.msg_flags,并且内核还会根据recvmsg的返回结果更新msg_flags;
* return : 成功返回读取/写入的字节数,失败返回-1,设置错误码;
*
* 通过设置sendmsg/recvmsg的参数msg,read、readv、recv、recvfrom和write、writev、send、sendto
* 等函数都可以对应换成这两个函数来调用;
* sendmsg/recvmsg的用法太灵活,这里就不记录具体的用法了;
*/
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
/*  结构体msghdr  详细说明可以见我的另一篇博客《linux/macos获取路由信息》*/
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_control表示的数据结构cmsghdr */
#include <sys/socket.h>
struct cmsghdr {
    socklen_t   cmsg_len;   /* length in bytes, including this structure */
    int         cmsg_level; /* originating protocol */
    int         cmsg_type;  /* protocol-specific type */
    /* followed by unsigned char cmsg_data[] */
}
//辅助数据可以用于通信时通信双方获取对方的一些其他的额外信息

recvmsg返回msg_flags含义(部分):

标志说明
MSG_BCAST它的返回条件是本数据包作为链路层广播收取或者其目的 IP 地址是一个广播地址,可用于判定一个 UPD 数据包是否发往某个广播地址
MSG_MCAST它的返回条件是本数据报作为链路层多播收取
MSG_TRUNC本标志的返回条件是本数据报被截断,内核预备返回的数据超过进程事先分配的空间(所有 iov_len 成员之和)
MSG_CTRUNC本标志的返回条件是本数据报的辅助数据被截断,内核预备返回的辅助数据超过进程事先分配的空间(msg_controllen)
MSG_EOR本标志的返回条件是返回数据结束一个逻辑记录;TCP 不使用本标志,因为它是一个字节流协议
MSG_OOB本标志绝不为 TCP 带外数据返回。它用于其他协议族(如 OSI 协议族)
MSG_NOTIFICATION本标志由 SCTP 接收者返回,指示读入的消息是一个事先通知,而不是数据消息

错误号

  • 获取错误码的方式
    包含头文件:
    #include < errno.h>
    引用的错误码变量名称:
    errno
    以字符串的方式输出错误码表示的含义:
    strerror(errno)

  • 表示需要重新处理的错误码

    • EAGAIN
      非阻塞模式下未得到期望的结果,等待下一次继续调用函数(linux下)
    • EWOULDBLOCK
      非阻塞模式下未得到期望的结果,等待下一次继续调用函数(windows下)
    • EINTR
      由于信号中断未得到期望的结果,等待下一次调用
  • 错误码(待更新…)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值