《Linux高性能服务器编程》学习笔记——第五章 Linux网络编程基础API(3)

下面学习Linux网络API的socket读写接口。


1、TCP数据读写

文件读写操作read和write同样可用于socket,但是socket编程接口提供了专门的系统调用。TCP读写系统调用为:

#include<sys/types.h>

#include<sys/socket.h>

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);

buf为缓冲区,len为大小,flags一般设为0。recv成功返回实际读取的数据长度,可能小于len,所以需要多次调用recv读取完整数据。返回0表示对方已关闭连接,出错返回-1并设置errno。send成功返回实际写入的数据长度,失败返回-1并设置errno。

flags提供了额外的控制选项,可选以下一个或多个标志(当前不明白其具体含义,后续研究):

MSG_CONFIRM:(send)指示数据链路层协议持续监听对方的回应,直到得到答复。仅用于SOCK_DGRAM和SOCK_RAW类型socket;

MSG_DONTROUTE:(send)不查看路由表,直接将数据发送给本地局域网主机,表示发送者确切知道目标主机就在本地网络;

MSG_DONTWAIT:(recv send )对socket的此次操作是非阻塞的;

MSG_MORE:(send)告诉内核应用程序还有更多数据要发送,内核将超时等待新数据写入TCP发送缓冲区后一并发送,防止TCP发送过多小的报文段,提高传输效率;

MSG_WAITALL:(recv)读操作仅在读取到指定数量的字节后才返回;

MSG_PEEK:(recv)窥探读缓存中的数据,此次读操作不会导致这些数据被清除;

MSG_OOB:(recv send)发送或接收紧急数据;

MSG_NOSIGNAL:(send)往读端关闭的管道或socket连接中写数据时不引发SIGPIPE信号;


2、UDP数据读写

UDP数据报读写系统调用:

#include<sys/types.h>

#include<sys/socket.h>

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t addrlen);

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

UDP没有连接的概念,每次读写需要获取对端的socket地址。参数和返回值含义与send/recv相同。

recvfrom/sendto也可以用于面向连接的socket数据读写,只要把后两个参数设为NULL。


3、通用数据读写

对于TCP和UDP,socket编程接口提供了一对通用的系统调用:

#include<sys/socket.h>

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

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

msghdr结构体定义:

struct msghdr

{

void* msg_name;                 /*socket地址*/

socklen_t msg_namelen;   /*socket地址长度*/

struct iovec* msg_iov;          /*分散内存块*/

int msg_iovlen;   /*分散内存块数量*/

void* msg_control;                /*辅助数据的起始位置*/

socklen_t msg_controllen;  /*辅助数据大小*/

int msg_flags;   /*复制函数中的flags参数,调用过程中更新*/

};

msg_name成员对TCP没有意义,必须设置为NULL。

iovec结构体定义:

struct iovec

{

void *iov_base;/*内存起始地址*/

size_t iov_len;/*内存长度*/
};

iovec封装了一块内存的起始地址和长度,msg_iovlen指定有多少个这样的结构体对象。

对于recvmsg,数据被读取并存放在msg_iovlen块分散的内存中,内存位置和长度由msg_iov数组指定,称为分散读(scatter read);

对于sendmsg,msg_iovlen块分散内存的数据被一并发送,称为集中写(gather write)。

flags参数和返回值跟recv/send相同。


4、带外标记

Linux内核检测到TCP紧急标志时将通知应用程序有带外数据需要接收,两种常见方式为I/O复用产生的异常事件和SIGURG信号。应用程序还需要知道带外数据在数据流中的具体位置:

#include<sys/socket.h>

int sockatmark(int sockfd);

sockatmark判断sockfd是否处于带外标记,即下一个被读到的数据是否是带外数据。如果是返回1,此时我们就可以利用带MSG_OOB标志的recv函数来接收带外数据;如果不是,返回0。


5、地址信息函数

获取一个连接socket的本端socket地址和远端socket地址:

#include<sys/socket.h>

int getsockname(int sockfd, struct sockaddr* address, socklen_t* address_len);

int getpeername(int sockfd, struct sockaddr* address, socklen_t* address_len);

getsockname获取sockfd的本端socket地址,存储在address指向的内存,长度存储在address_len中,若地址长度超过address内存区,截断。成功返回0,失败返回-1并设置errno。

getpeername获取远端socket地址,与getsockname类似。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值