文章目录
  1. 数据读写
    1. TCP数据读写
    2. UDP数据读写
    3. 通用数据读写
  2. 接收带外标记
  3. 地址信息函数

数据读写

TCP数据读写

socket编程接口提供了专门用于socket数据读写的函数,它们增加对数据读写的控制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
引用方式: #include <sys/socket.h>
buf: 读/写缓冲区的地址
len: 读/写缓冲区的大小
flags: 为数据收发提供相应控制
MSG_CONFIRM: 指示数据链路层协议持续监听对方的回应, 直到得到回复; 仅能用于SOCK_DGRAM/SOCK_RAW类型的socket; 只能用于send函数
MSG_DONTROUTE: 不查看路由表, 直接将数据发送给本地局域网内的主机; 只能用于send函数
MSG_DONTWAIT: 对该socket的此次操作是非阻塞的
MSG_MORE: 告知内核应用程序还有更多数据要发送, 内核将超时等待新的数据写入TCP发送缓冲区后一并发送; 只能用于send函数
MSG_WAITALL: 读操作仅在读取到指定数量的字节后才返回; 只能用于recv函数
MSG_PEEK: 窥探读缓存的数据, 此次读操作不会导致这些数据被清除; 只能用于recv函数
MSG_OOB: 发送或接收紧急数据
MSG_NOSIGNAL: 向读端关闭的管道或socket连接中写数据时不引发SIGPIPE信号
返回实际读取/写入的数据: 成功 || 返回-1并设置errno: 失败
*/
ssize_t recv(int sockfd, void * buf, size_t len, int flags);

ssize_t send(int sockfd, const void * buf, size_t len, int flags);

UDP数据读写

1
2
3
4
5
6
7
8
9
10
11
12
/*
引用方式: #include <sys/socket.h>
buf: 读/写缓冲区的地址
len: 读/写缓冲区的大小
flags: 为数据收发提供相应控制, 选项与意义与send/recv的flags相同
addr: 发送/接收端的socket地址
addr_len: 发送/接收端的socket地址长度
返回实际读取/写入的数据: 成功 || 返回-1并设置errno: 失败
*/
ssize_t recvfrom(int sockfd, void * buf, size_t len, int flags, struct sockaddr * addr, socklen_t * addr_len);

ssize_t sendto(int sockfd, const void * buf, size_t len, int flags, const struct sockaddr * addr, socklen_t addr_len);

若将参数addr与addr_len置为NULL,则recvfrom/sendto也可用于面向连接的socket数据读写。

通用数据读写

socket编程接口提供一对通用的数据读写系统调用。既可用于TCP流数据,又可以用于UDP数据报。

1
2
3
4
5
6
7
/*
引用方式: #include <sys/socket.h>
返回实际读取/写入的数据: 成功 || 返回-1并设置errno: 失败
*/
ssize_t recvmsg(int sockfd, struct msghdr * msg, int flags);

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

其中,结构体msghdr的定义如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
引用方式: #include <sys/socket.h>
msg_name: socket地址(同样对于TCP连接, 此项设置为NULL)
msg_namelen: socket地址长度
msg_iov: 分散的内存块
msg_iovlen: 分散的内存块的数量
msg_control: 辅助数据的起始地址
msg_controllen: 辅助数据的大小
msg_flags: 复制函数中的flags参数, 并在调用过程中更新
*/
struct msghdr{
void *msg_name;
socklen_t msg_namelen;
struct iovec *msg_iov;
size_t msg_iovlen;
void *msg_control;
size_t msg_controllen;
int msg_flags;
};

其中,结构体iovec的定义如下。

1
2
3
4
5
6
7
8
9
/*
引用方式: #include <sys/socket.h>
iov_base: 内存起始地址
iov_len: 这段内存长度
*/
struct iovec{
void *iov_base;
size_t iov_len;
};

接收带外标记

在recv函数的flags中设置MSG_OOB选项可以接收带外数据,但是实际应用中程序无法预期带外数据何时到来;因此,Linux提供sockatmark函数来判断sockfd是否处于带外标记,即下一个被读取的数据是否为带外数据;如果是,sockatmark函数返回1。

1
2
3
4
/*
引用方式: #include <sys/socket.h>
*/
int sockatmark(int sockfd);

地址信息函数

想知道一个连接socket的本端socket地址与远端socket地址,Linux提供如下两个函数。

1
2
3
4
5
6
7
8
9
10
/*
引用方式: #include <sys/socket.h>
sockfd: 要查询本端/远端socket地址的连接socket
addr: 存放查询结果的地址
len: 存放查询结果的长度, 可使用sizeof(struct sockaddr)
返回0: 成功 || 返回-1并设置errno: 失败
*/
int getsockname(int sockfd, struct sockaddr * addr, socklen_t len);

int getpeername(int sockfd, struct sockaddr * addr, socklen_t len);