前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux网络编程API(二)

Linux网络编程API(二)

作者头像
doper
发布2022-09-26 17:39:28
1K0
发布2022-09-26 17:39:28
举报
文章被收录于专栏:后台技术杂项笔记

相关API笔记(二)

Linux网络编程高级I/O函数

1. pipe

pipe函数用于创建一个管道,实现进程间通信

代码语言:javascript
复制
#include <unistd.h>
//成功返回0,失败返回-1并设置errno
int pipe(int fd[2]);

参数:

fd: pipe函数创建的两个文件描述符对应管道两端,分别为“读”端“写端”(可记忆为读写),即fd[0]为管道的读端,fd[1]为管道的写端。

默认情况下这对文件描述符是阻塞的,对空的fd[0]执行读操作对满的fd[1]执行写操作会阻塞。

创建双向管道

代码语言:javascript
复制
#include <sys/types.h>
#include <sys/socket.h>
//成功返回0,失败返回-1并设置errno
int socketpair(int domain, int type, int protocol, int fd[2]);

参数:

前三个参数与socket系统调用的三个参数完全相同,但是domian只能使用UNIX本地域协议族AF_UNIX,因为仅能在本地使用这个双向管道

fd: 与pipe系统调用的参数一样,不过这里创建的文件描述符都是即可读又可写的

2. dup和dup2

代码语言:javascript
复制
#include <unistd.h>
//二者都是失败返回-1并设置errno
int dup(int file_descriptor);
//dup2可理解为后者重定向到前者
int dup2(int file_descriptor_one, int file_descriptor_two);

参数:

dup和dup2的参数都是文件描述符,具体作用如下:

dup函数创建一个新的文件描述符,该新的描述符和原有文件描述符file_descriptor指向相同文件,管道或者网络连接, 并且dup返回的文件描述符总是取系统当前可用的最小整数值

dup2函数与dup类似,不过它返回的是第一个不小于file_descriptor_tow的整数值

代码语言:javascript
复制
//例子。重定向STDOUT
//使用dup
void dup_out(){
    //...
    close(STDOUT);
    dup(fd);
    printf("dup");
    close(fd);
}

//使用dup2
void dup2_out(){
    dup2(fd, STDOUT);
    printf("dup2");
    close(fd);
}

3. readv和writev

readv函数将数据从文件描述符读到分散的内存块中,即分散读

writev函数则将多块分散的内存数据一并写入文件描述符中,即集中写

代码语言:javascript
复制
#include <sys/uio.h>
ssize_t readv(int fd, const struct iovec* vector, int count);
ssize_t writev(int fd, const struct iovec* vector, int count);
//iovec封装了一块内存的起始位置和长度
struct iovec{
    void*		iov_base;				//内存起始地址
    size_t 		iov_len;				//这块内存的长度
};

参数:

fd: 被操作的目标文件描述符

vector: iovec结构数组

count: vector数组的长度

代码语言:javascript
复制
//eg
char buf1[1024], buf2[1024];
//...往buf1填充数据
struct iovec iv[2];
iv[0].iov_base = buf1;
iv[0].iov_len = sizeof(buf1);
iv[1].iov_base = buf2;
iv[1].iov_len = sizeof(buf2);
//writev,集中写,把buf1,buf2中的数据写到connfd
ret = writev(connfd, iv, 2);
//readv,分散读,把键盘的输入读出并放入到buf1,buf2中
ret = readv(STDIN_FILENO, iv, 2);

3. sendfile

sendfile函数在两个文件描述符之间直接传递数据(完全在内核中操作),避免在内核缓冲区和用户缓冲区之间的数据拷贝,效率很高,称为零拷贝

代码语言:javascript
复制
#include <sys/sendfile.h>
//成功返回传输的字节数,失败返回-1并设置errno
ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count);

参数:

out_fd: 待写入内容的文件描述符,可理解为数据进入到out_fd输出,流到in_fd,我们需要把数据写给它让它又得输出。

in_fd: 待读出内容的文件描述符,可理解为文件流入到in_fd中,我们需要从它这里读出数据。

offset: 指定从读入文件流的哪个位置开始读,如果为空,则使用读入文件流默认的起始位置。

count: 指定在文件描述符in_fd和out_fd之间传输的字节数

4. mmap和munmap

mmap用于申请一段内存空间,这段内存可以作为进程间通信的共享内存,可以将文件直接映射到其中。

munmap函数则释放mmap创建的这段内存空间

代码语言:javascript
复制
#include <sys/mman.h>
//成功返回指向目标区域的指针,失败返回MAP_FAILED((void*)-1)
void* mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
//成功返回0,失败返回-1并设置errno
int munmap(void *start, size_t length);

参数:

start: 用户指定某个特定的地址作为这段内存的起始地址,如果设置为NULL,则系统自动分配一个地址。

length: 指定内存段的长度

prot: 设置内存段的访问权限

含义

PROT_READ

内存段可读

PROT_WRITE

内存段可写

PROT_EXEC

内存段可执行

PROT_NONE

内存段不能访问

flags:可控制内存段内容被修改后程序的行为

mmap.png
mmap.png

5. splice

splice函数用于在两个文件描述符之间移动数据,也是零拷贝操作

代码语言:javascript
复制
#include <fcntl.h>
//成功返回移动字节的数量,失败返回-1并设置errno
ssize_t splice(int fd_in, loof_t* off_in, int fd_out, loff_t* off_out, size_t len, unsigned int flags);

参数:

fd_in: 待输入数据的文件描述符

off_in: 如果fd_in是管道文件描述符,则必须设置为NULL,若不是(如socket),则off_in表示从输入数据流的何处开始读取数据。

fd_out: 待输出数据的文件描述符

off_out: 同off_in

len: 指定移动数据的长度

flags: 可被设置为如下某些值的按位或

ff22.png
ff22.png

使用splice时,fd_in和fd_out至少有一个是管道文件描述符

其常见errno:

errno.png
errno.png

6. tee

tee函数用于在两个管道文件描述符之间复制数据,也是零拷贝操作

代码语言:javascript
复制
#include <fcntl.h>
//成功返回复制的数据量,失败返回-1并设置errno
ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);

参数:

与splice相同,但是fd_infd_out必须都是管道文件描述符

代码语言:javascript
复制
//eg
//把管道pipe1的输出端数据复制到管道pipe2的输入端
int ret = tee(pipe1[0], pipe2[1], 32768, SPLICE_F_NONBLOCK);

7. fcntl

fctnl(file control), 提供对文件描述符的各种控制操作

代码语言:javascript
复制
#include <fctnl.h>
//成功返回值见后面表格,失败返回-1并设置errno
int fcntl(int fd, int cmd, ...);

参数:

fd: 被操作的文件描述符

cmd: 操作类型,根据操作类型可能还需要第三个可选参数arg

fctnl1.png
fctnl1.png
fctnl2.png
fctnl2.png

对于F_SETFL,可更改的几个标志如下面的描述:

  • O_NONBLOCK 非阻塞I/O,如果read(2)调用没有可读取的数据,或者如果write(2)操作将阻塞,则read或write调用将返回-1和EAGAIN错误
  • O_APPEND 强制每次写(write)操作都添加在文件大的末尾,相当于open(2)的O_APPEND标志
  • O_DIRECT 最小化或去掉reading和writing的缓存影响。系统将企图避免缓存你的读或写的数据。如果不能够避免缓存,那么它将最小化已经被缓存了的数据造成的影响。如果这个标志用的不够好,将大大的降低性能
  • O_ASYNC 当I/O可用的时候,允许SIGIO信号发送到进程组,例如:当有数据可以读的时候
代码语言:javascript
复制
//eg
int setnonblocking(int fd){
    int old_option = fctnl(fd, F_GETFL);	/* 获取文件描述符旧的状态标志 */
    int new_option = old_option | O_NONBLOCK;	/* 设置非阻塞标志 */
    fcntl(fd, F_SETFL, new_option);
    return old_option;	/* 返回文件描述符旧的状态标志,以便日后恢复该状态标志 */
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-03-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 相关API笔记(二)
  • 1. pipe
  • 2. dup和dup2
  • 3. readv和writev
  • 3. sendfile
  • 4. mmap和munmap
  • 5. splice
  • 6. tee
  • 7. fcntl
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档