分类
Linux网络API可以分成三类
- socket地址API,socket指的是一个(ip,port)对,唯一地标记了TCP通信的一端。
- socket基础API,主要是指sys/socket.h头文件中,socket创建,命名,监听,接受连接,发起连接,读写数据,获取地址信息,检测带外标记,以及读取和设置socket选项。
- 网络信息API,实现主机名和IP地址之间的转换,以及服务名称和端口号之间的转换。
创建socket
int socket(int domain,int type,int protocol)
- domain指的是使用的协议簇,可选的有PF_INET(ipv4),PF_INET6(ipv6),PF_UNIX(unix)
- type指的是服务类型,可以选数据报服务,数据流服务,更新后也可能传入非阻塞,和在fork时关闭socket的参数
- protocol指的是协议,其实前两个参数已经能确定一个协议了。
- 创建socket成功则返回一个文件描述符。
命名socket
int bind(int sockfd,const struct sockaddr * my_addr,socklen_t addrlen )
- 把my_addr指向的地址分配给文件描述符,addrlen参数指的是该socket地址的长度。
- bind成功时返回0,失败返回-1并设置errno。其中两种常见的errno是EACCES和EADDRINUSE,它们的含义分别是地址被保护需要超级用户才能访问,绑定的地址正在使用中。
监听socket
int listen(int sockfd,int backlog)
- sockfd指定被监听的socket
- backlog指内核监听队列的最大长度,如果监听队列的长度超过该值,服务器将不受理新的客户连接,指定值是半连接长度+全连接长度的上限。
- listen成功返回0,失败返回-1.
接受连接
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen)
- 已经调用listen的socket
- 远端的地址
- socket地址的长度
- accept成功时返回一个新的socket,服务器可通过读写该socket来与客户端进行通信。
- 这里有一点,客户端握手成功后立马宕机,这时候服务端是无感知的。
发起连接
int connect(int sockfd,const struct sockaddr *serv_addr,socklen_t addrlen)
- serv_addr是指服务端监听的地址
- sockefd成功后返回一个socket,唯一地标识一个连接。
- 可能会出现目标端口不存在或连接超时的可能。
关闭连接
int close(int fd)
- fd指待关闭的连接,不是立马关闭一个连接,将fd的引用计数器减一,等到计数为0时才关闭连接。
- 在fork进程时,系统调用会默认将父进程的socket的引用计数加1.
数据读写
TCP读写
1 | c复制代码ssize_t recv(int sockfd,void *buf,size_t len,int flags) |
- recv读取sockfd上的数据,buf和len参数分别指定读缓冲区的位置和大小
- 成功时返回读取的数据长度
UDP读写
1 | c复制代码ssize_t recvfrom(int sockfd,void* buf,size_t len,int flags,struct sockaddr* src_addr,socklen_t* addrlen); |
- 由于UDP无连接,所以每一次都要获取发送端的地址。
高级IO函数
pipe()
int pipe(int fd[2])
- pipe可以创建一个管道,以实现进程通信
- 参数包含两个int型整数的数组指针。该函数成功时返回0,并将一对打开的文件描述符值填入数组中。
- fd[0]和fd[1]分别构成管道的两端,使用的方向确定,不能反过来使用,如果想要实现双向通信,就应该使用两个管道。
- 管道默认阻塞的。
- 管道的默认大小为65535字节。
dup函数和dup2函数
1 | c复制代码int dup(int file_descriptor) |
- 如果我们想把标准输入重定向到应该文件,或者把标准输出重定向到网络连接中,可以使用这两个函数
- dup创建一个新的文件描述符,该新文件描述符和原有的文件描述符指向同一个文件,管道或网络连接,并且dup返回的文件描述符总是取系统当前可用的最小整数值,dup2返回第一个不小于file_descriptor_two的整数值。
readv函数和writev函数
分散读
集中写
sendfile
ssize_t sendfile(int out_fd,int in_fd,off_t *offset,size_t count)
- 在两个文件描述符之间直接传递数据,避免了在内核缓冲区和用户缓冲区之间的数据拷贝,效率很高,被称为零拷贝。
- in_fd必须指向一个真实文件,out_fd必须是一个socket
mmap函数和munmap函数
1 | c复制代码void* mmap(void *start,size_t length,int prot,int flags,int fd,off_t offset) |
- mmap函数用于申请一段内存空间,我们可以将这段内存作为进程间通信的共享内存,也可以将文件直接映射到其中
- munmap函数则释放由mmap创建的这段空间
- start起始地址,可以由系统分配
- prot指的是内存权限。
splice函数
ssize_t splice(int fd_in,loff_t* off_in,int fd_out,loff_t* off_out,size_t len,nusigned int flags)
- 在两个文件描述符间移动数据,也就是零拷贝。
tee函数
ssize_t tee(int fd_in,int fd_out,size_t len,unsigned int flags)
- 在两个管道间复制数据
本文转载自: 掘金