- 用于创建文件描述符的函数,包括pipe、dup/dup2函数
-
用于读写数据的函数,包括readv/writev、sendfile、mmap/munmap、splice和tee函数。
- 用于控制I/O行为和属性的函数,包括fcntl函数。
1.Pipe函数
pipe函数用于创建一个管道
#include<unistd.h> int pipe(int fd[2]); //成功返回0 失败返回-1并设置 errno fd[0]负责写入 fd[1]从管道读取数据
//如果想实现双i昂的数据传输 应该使用两个管道 默认read write都是堵塞的
2.socketpair函数
#include<sys/types.h> #include<sys/socket.h> int socketpair(int domain,int type,int protocol,int fd[2]);
//成功返回0 失败返回-1并设置 errno
- socketpair前三个参数的含义与socket系统调用的三个参数相同 但domain只能使用UNIX本地域协议族AF_UNIX
- socketpair创建的这对文件描述符都是既可读又可写的
3.dup函数和dup2函数 (复制文件述符file_descriptor
#include<unistd.h> int dup(int file_descriptor); //dup函数创建一个新的文件描述符,该新文件描述符和原有文件描述符file_descriptor
指向相同的文件、管道或者网络连接。
int dup2(int file_descriptor_one,int file_descriptor_two); //dup2和dup类似,不过它将返回第一个不小于file_descriptor_two的整数值。
dup和dup2系统调用失败时返回-1并设置errno。
- 把标准输入重定向到一个文件,或者把标准输出重定
- 向到一个网络连接(比如CGI编程)
- CGI 服务器
// // Created by jignchu on 11/25/18. // #include <stdio.h> #include <sys/types.h> #include <arpa/inet.h> #include <sys/socket.h> #include <stdlib.h> #include <assert.h> #include <strings.h> #include <errno.h> #include <string.h> #include <unistd.h> int main(int argc ,char *argv[]){ if (argc < 2) { printf("userage:%s ip_address port number",argv[0]); return 1; } const char *ip = argv[1]; int port =atoi(argv[2]); //stdlib.h trim space convert string to int type struct sockaddr_in address; bzero(&address, sizeof(address)); address.sin_family = AF_INET; inet_pton(AF_INET,ip,&address.sin_addr); //ipv4 address network show address.sin_port = htons(port); int sock = socket(PF_INET,SOCK_STREAM,0); assert(sock>=0); int ret = bind(sock,(struct sockaddr*)&address, sizeof(address)); assert(ret!=-1); ret = listen(sock,5); assert(ret!=-1); struct sockaddr_in client; socklen_t client_addrlength = sizeof(client); int connfd = accept(sock,(struct sockaddr*)&client,&client_addrlength); if (connfd < 0) { printf("error is %d",errno); } else{ close(STDOUT_FILENO); dup(connfd); printf("abcd\n"); close(connfd); } close(sock); return 0; }
4.readv函数和writev函数
- readv函数将数据从文件描述符读到分散的内存块中,即分散读
- writev函数则将多块分散的内存数据一并写入文件描述符中,即集中写
#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);
fd参数是被操作的目标文件描述符。 vector参数的类型是iovec结构数组 count参数是vector数组的长度
readv和writev在成功时返回读出/写入fd的字节数,失败则返回-1
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
// // Created by jignchu on 11/25/18. // #include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <stdbool.h> #include <libgen.h> #include <fcntl.h> #include <sys/stat.h> #include <unistd.h> #include <sys/uio.h> #include <stddef.h> #define BUFFER_SIZE 1024 static const char* status_line[2] = {"200 OK","500 Internal server error"}; int main(int argc, char *argv[]){ if (argc < 3) { printf("useage:%s ip_address port_number filename\n",basename(argv[0])); return 1; } const char *ip = argv[1]; int port = atoi(argv[2]); const char *file_name = argv[3];// the third val is dst file struct sockaddr_in address; bzero(&address, sizeof(address)); address.sin_family=AF_INET; inet_pton(AF_INET,ip,&address.sin_addr); address.sin_port = htons(port); int sock = socket(AF_INET,SOCK_STREAM,0); assert(sock>0); int ret = bind(sock,(struct sockaddr*)&address, sizeof(address)); assert(ret!=-1); struct sockaddr_in client; socklen_t client_addrlength = sizeof(client); int connfd = accept(sock,(struct sockaddr*)&client,&client_addrlength); if (connfd < 0) { printf("error is %d\n",errno); } else{ char header_buf[BUFFER_SIZE]; memset(header_buf,'\0', BUFFER_SIZE); char *file_buf; struct stat file_stat;// get dst file properties file size isDirectory bool valid = true; int len = 0; if (stat(file_name, &file_stat) < 0) { valid = false; }else{ if(S_ISDIR(file_stat.st_mode)){ valid = false; }else if(file_stat.st_mode&S_IROTH){ int fd = open(file_name,O_RDONLY); file_buf = new char[file_stat.st_size+1]; memset(file_buf,'\n',file_stat.st_size+1); if (read(fd, file_buf, file_stat.st_size) < 0) { valid = false; } } else{ valid = false; } } if (valid) { ret = snprintf(header_buf,BUFFER_SIZE-1,"%s%s\r\n","HTTP/1.1",status_line[0]); len+=ret; ret = snprintf(header_buf+len,BUFFER_SIZE-1-len,"Content-Length:%d\r\n",file_stat.st_size); len+=ret; ret = snprintf(header_buf+len,BUFFER_SIZE-len-1,"%s","\r\n"); struct iovec iv[2]; iv[0].iov_base = header_buf; iv[0].iov_len = strlen(header_buf); iv[1].iov_base = file_buf; iv[1].iov_len = file_stat.st_size; ret = writev(connfd,iv,2); }else{ ret = snprintf(header_buf,BUFFER_SIZE-1,"%s%s\r\n","HTTP/1.1",status_line[1]); len+=ret; ret = snprintf(header_buf+len,BUFFER_SIZE-1-len,"%s","\r\n"); send(connfd,header_buf,strlen(header_buf),0); } close(connfd); delete[] file_buf; } close(sock); return 0; }
5.(突然看见的) stat函数
相关函数:fstat, lstat, chmod, chown, readlink, utime
头文件:#include<sys/stat.h> #include<uninstd.h>
定义函数:int stat(const char * file_name, struct stat *buf);
函数说明:stat()用来将参数file_name 所指的文件状态, 复制到参数buf 所指的结构中。
下面是struct stat 内各参数的说明:
struct stat { dev_t st_dev; //device 文件的设备编号 ino_t st_ino; //inode 文件的i-node mode_t st_mode; //protection 文件的类型和存取的权限 nlink_t st_nlink; //number of hard links 连到该文件的硬连接数目, 刚建立的文件值为1. uid_t st_uid; //user ID of owner 文件所有者的用户识别码 gid_t st_gid; //group ID of owner 文件所有者的组识别码 dev_t st_rdev; //device type 若此文件为装置设备文件, 则为其设备编号 off_t st_size; //total size, in bytes 文件大小, 以字节计算 unsigned long st_blksize; //blocksize for filesystem I/O 文件系统的I/O 缓冲区大小. u nsigned long st_blocks; //number of blocks allocated 占用文件区块的个数, 每一区块大小为512 个字节. time_t st_atime; //time of lastaccess 文件最近一次被存取或被执行的时间, 一般只有在用mknod、 utime、read、write 与tructate 时改变. time_t st_mtime; //time of last modification 文件最后一次被修改的时间, 一般只有在用mknod、 utime 和write 时才会改变 time_t st_ctime; //time of last change i-node 最近一次被更改的时间, 此参数会在文件所有者、组、 权限被更改时更新 };
先前所描述的st_mode 则定义了下列数种情况:
S_IFMT 0170000 文件类型的位遮罩 S_IFSOCK 0140000 scoket S_IFLNK 0120000 符号连接 S_IFREG 0100000 一般文件 S_IFBLK 0060000 区块装置 S_IFDIR 0040000 目录 S_IFCHR 0020000 字符装置 S_IFIFO 0010000 先进先出 S_ISUID 04000 文件的 (set user-id on execution)位 S_ISGID 02000 文件的 (set group-id on execution)位 S_ISVTX 01000 文件的sticky 位 S_IRUSR (S_IREAD) 00400 文件所有者具可读取权限 S_IWUSR (S_IWRITE)00200 文件所有者具可写入权限 S_IXUSR (S_IEXEC) 00100 文件所有者具可执行权限 S_IRGRP 00040 用户组具可读取权限 S_IWGRP 00020 用户组具可写入权限 S_IXGRP 00010 用户组具可执行权限 S_IROTH 00004 其他用户具可读取权限 S_IWOTH 00002 其他用户具可写入权限 S_IXOTH 00001 其他用户具可执行权限上述的文件类型在 POSIX 中定义了检查这些类型的宏定义 S_ISLNK (st_mode) 判断是否为符号连接 S_ISREG (st_mode) 是否为一般文件 S_ISDIR (st_mode) 是否为目录 S_ISCHR (st_mode) 是否为字符装置文件 S_ISBLK (s3e) 是否为先进先出 S_ISSOCK (st_mode) 是否为socket 若一目录具有sticky 位 (S_ISVTX), 则表示在此目录下的文件只能 被该文件所有者、此目录所有者或root 来删除或改名.
返回值:执行成功则返回0,失败返回-1,错误代码存于errno。
错误代码:
1、ENOENT 参数file_name 指定的文件不存在 2、ENOTDIR 路径中的目录存在但却非真正的目录 3、ELOOP 欲打开的文件有过多符号连接问题, 上限为16 符号连接 4、EFAULT 参数buf 为无效指针, 指向无法存在的内存空间 5、EACCESS 存取文件时被拒绝 6、ENOMEM 核心内存不足 7、ENAMETOOLONG 参数file_name 的路径名称太长
#include <sys/stat.h> #include <unistd.h> int main() { struct stat buf; stat("/etc/passwd", &buf); printf("/etc/passwd file size = %d \n", buf.st_size); }
6.(突然看见的)sprintf()
int sprintf( char *buffer, const char *format [, argument] … );
除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,显然就在第二个参数:格式化字符串上。
- 1.格式化数字字符串
sprintf
(s,
"%d"
, 123);
- 2.控制浮点数打印格式
sprintf
(s,
"%10.3f"
, 3.1415626);
-
for (int i = 32; i < 127; i++) { printf("[ %c ]: %3d 0x%#04X/n", i, i, i); }
- 3.连接字符串
sprintf(s, "%s love %s.", who, whom);
6.snprintf()
int snprintf(char *restrict buf, size_t n, const char * restrict format, ...);
函数说明:最多从源串中拷贝 n-1 个字符到目标串中,然后再在后面加一个 '\0'。所以如果目标串的大小为 n 的话,将不会溢出。
#include <stdio.h> int main(int argc, char **argv) { char str[10] = {0}; snprintf(str, sizeof(str), "0123456789012345678"); printf("str=%s\n", str); return 0; }
7.iovec结构体定义及使用
#include <sys/uio.h> struct iovec { ptr_t iov_base; /* Starting address */ size_t iov_len; /* Length in bytes */ };
struct iovec定义了一个向量元素。通常,这个结构用作一个多元素的数组。对于每一个传输的元素,指针成员iov_base指向一个缓冲区,这个缓冲区是存放的是readv所接收的数据或是writev将要发送的数据。成员iov_len在各种情况下分别确定了接收的最大长度以及实际写入的长度。
int readv(int fd, const struct iovec *vector, int count); int writev(int fd, const struct iovec *vector, int count);
8.sendfile函数
sendfile函数在两个文件描述符之间直接传递数据(完全在内核中操
作),从而避免了内核缓冲区和用户缓冲区之间的数据拷贝,效率很
高,这被称为零拷贝。
#include<sys/sendfile.h> ssize_t sendfile(int out_fd,int in_fd,off_t*offset,size_t count);
in_fd参数是待读出内容的文件描述符 in_fd必须是一个支持类似mmap函数的文件描述符它必须指向真实的文件
out_fd参数是待写入内容的文件描述符 而out_fd则必须是一个socket。
offset参数指定从读入文件流的哪个位置开始 如果为空,则使用读入文件流默认的起始位置
count参数指定在文件描述符in_fd和out_fd之间传输的字节数
sendfile成功时返回传输的字节数败则返回-1并设置errno。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
// // Created by jignchu on 11/25/18. // #include <sys/types.h> #include <stdio.h> #include <libgen.h> #include <stdlib.h> #include <fcntl.h> #include <assert.h> #include <sys/stat.h> #include <netinet/in.h> #include <strings.h> #include <arpa/inet.h> #include <errno.h> #include <sys/sendfile.h> #include <unistd.h> int main(int argc, char *argv[]){ if (argc < 3) { printf("useage:%s ip_address port_number filename\n", basename(argv[0])); return 1; } const char* ip = argv[1]; // get ip int port = atoi(argv[2]); const char *file_name = argv[3]; int filefd = open(file_name,O_RDONLY); assert(filefd>0); struct stat stat_buf; fstat(filefd,&stat_buf); struct sockaddr_in address;//#include <netinet/in.h> bzero(&address, sizeof(address));//strings.h inet_pton(AF_INET,ip, &address.sin_addr); //arpa/inet.h address.sin_port = htons(port); int sock = socket(PF_INET,SOCK_STREAM,0); assert(sock>0); int ret = bind(sock,(struct sockaddr*)&address, sizeof(address)); assert(ret!=-1); ret = listen(sock,5); assert(ret!=-1); struct sockaddr_in client; socklen_t client_length = sizeof(address); int connfd = accept(sock,(struct sockaddr*)&client,&client_length); if (connfd < 0) { printf("error is %s\n",errno); }else{ sendfile(connfd,filefd,NULL,stat_buf.st_size); close(connfd); } }
9.open函数
open函数属于Linux中系统IO,用于“打开”文件,代码打开一个文件意味着获得了这个文件的访问句柄。
int open( const char * pathname, int flags); int open( const char * pathname,int flags, mode_t mode);
1.O_RDONLY 只读打开。
2.O_WRONLY 只写打开。
3.O_RDWR 读、写打开。 互斥的
4.O_APPEND 每次写时都加到文件的尾端。
5.O_CREAT 若此文件不存在则创建它。使用此选择项时,需同时说明第三个参数mode,用其说明该新文件的存取许可权位。
6.O_EXCL 如果同时指定了O_CREAT,而文件已经存在,则出错。这可测试一个文件是否存在,如果不存在则创建此文件成为一个原子操作。
7.O_TRUNC 如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0。
8.O_NOCTTY 如果pathname指的是终端设备,则不将此设备分配作为此进程的控制终端。
9.O_NONBLOCK 如果pathname指的是一个F I F O、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I / O操作设置非阻塞方式。
10.O_NDELAY所产生的结果使I/O变成非阻塞模式(non-blocking),在读取不到数据或是写入缓冲区已满会马上return,而不会阻塞等待。
11.O_SYNC 使每次w r i t e都等到物理I / O操作完成。
12.O_APPEND 当读写文件时会从文件尾开始移动,也就是所写入的数据会以附加的方式加入到文件后面。
13.O_NOFOLLOW 如果参数pathname 所指的文件为一符号连接,则会令打开文件失败。
14.O_DIRECTORY 如果参数pathname 所指的文件并非为一目录,则会令打开文件失败。
注意:
(1)这些控制字都是通过“或”符号分开(|)
(2)O_NONBLOCK和O_NDELAY所产生的结果都是使I/O变成非阻塞模式(non-blocking),在读取不到数据或是写入缓冲区已满会马上return,而不会阻塞等待。
它们的差别在于:在读操作时,如果读不到数据,O_NDELAY会使I/O函数马上返回0,但这又衍生出一个问题,因为读取到文件末尾(EOF)时返回的也是0,这样无法区分是哪种情况。因此,O_NONBLOCK就产生出来,它在读取不到数据时会回传-1,并且设置errno为EAGAIN。
O_NDELAY是在System V的早期版本中引入的,在编码时,还是推荐POSIX规定的O_NONBLOCK,O_NONBLOCK可以在open和fcntl时设置
(3)Linux2.2以后特有的旗标,以避免一些系统安全问题。参数mode 则有下列数种组合,只有在建立新文件时才会生效,此外真正建文件时的权限会受到umask值所影响,因此该文件权限应该为(mode-umaks)。
S_IRWXU00700 权限,代表该文件所有者具有可读、可写及可执行的权限。
S_IRUSR 或S_IREAD,00400权限,代表该文件所有者具有可读取的权限。
S_IWUSR 或S_IWRITE,00200 权限,代表该文件所有者具有可写入的权限。
S_IXUSR 或S_IEXEC,00100 权限,代表该文件所有者具有可执行的权限。
S_IRWXG 00070权限,代表该文件用户组具有可读、可写及可执行的权限。
S_IRGRP 00040 权限,代表该文件用户组具有可读的权限。
S_IWGRP 00020权限,代表该文件用户组具有可写入的权限。
S_IXGRP 00010 权限,代表该文件用户组具有可执行的权限。
S_IRWXO 00007权限,代表其他用户具有可读、可写及可执行的权限。
S_IROTH 00004 权限,代表其他用户具有可读的权限
S_IWOTH 00002权限,代表其他用户具有可写入的权限。
S_IXOTH 00001 权限,代表其他用户具有可执行的权限。
原文:https://blog.csdn.net/weibo1230123/article/details/79036611
10.fstat函数
#include <sys/stat.h> #include <unistd.h> int fstat(int fildes, struct stat *buf); 函数说明:fstat()用来将参数fildes 所指的文件状态, 复制到参数buf 所指的结构中 (struct stat). fstat()与stat()作用完全相同, 不同处在于fstat()传入的参数为已打开的文件描述词.
#include <sys/stat.h> #include <unistd.h> #include <fcntk.h> main() { struct stat buf; int fd; fd = open("/etc/passwd", O_RDONLY); fstat(fd, &buf); printf("/etc/passwd file size +%d\n ", buf.st_size); } 原文:https://blog.csdn.net/qq_26093511/article/details/60109316
11.mmap() 和 munmap()
- mmap函数用于申请一段内存空间。我们可以将这段内存作为进程
- 间通信的共享内存,也可以将文件直接映射到其中。munmap函数则释放由mmap创建的这段内存空间。
#include<sys/mman.h> void*mmap(void*start,size_t length,int prot,int flags,int fd,off_t offset); int munmap(void*start,size_t length);
- start参数允许用户使用某个特定的地址作为这段内存的起始地址。如果它被设置成NULL,则系统自动分配一个地址。
- length参数指定内存段的长度。
- prot参数用来设置内存段的访问权限。它可以取以下几个值的按位或
PROT_READ,内存段可读。
PROT_WRITE,内存段可写。
PROT_EXEC,内存段可执行。
PROT_NONE,内存段不能被访问。
- flags参数控制内存段内容被修改后程序的行为 (MAP_SHARED和MAP_PRIVATE是互斥的,不能同时指定
- fd参数是被映射文件对应的文件描述符。它一般通过open系统调用获得
- offset参数设置从文件的何处开始映射(对于不需要读入整个文件的情况)。
- mmap函数成功时返回指向目标内存区域的指针,失败则返回MAP_FAILED((void*)-1)并设置errno
-
munmap函数成功时返回0,失败则返回-1并设置errno。
12.splice函数
splice函数用于在两个文件描述符之间移动数据,也是零拷贝操作。
#include<fcntl.h> ssize_t splice(int fd_in,loff_t*off_in,int fd_out,loff_t*off_out,size_t len,unsigned int flags);
- fd_in参数是待输入数据的文件描述符。如果fd_in是一个管道文件 描述符,那么off_in参数必须被设置为NULL。
- 如果fd_in不是一个管道 文件描述符(比如socket),那么off_in表示从输入数据流的何处开始读取数据。
- 此时,若off_in被设置为NULL,则表示从输入数据流的当前偏移位置读入;若off_in不为NULL,则它将指出具体的偏移位置.
- fd_out/off_out参数的含义与fd_in/off_in相同,不过用于输出数据流。len参数指定移动数据的长度;flags参数则控制数据如何移动,
- 使用splice函数时,fd_in和fd_out必须至少有一个是管道文件描述符。
- splice函数调用成功时返回移动字节的数量。
- 它可能返回0,表示没有数据需要移动,这发生在从管道中读取数据(fd_in是管道文件描述符)而该管道没有被写入任何数据时。
- splice函数失败时返回-1并设置
int pipefd[2]; assert(ret!=-1); ret=pipe(pipefd);/*创建管道*/ /*将connfd上流入的客户数据定向到管道中*/ ret=splice(connfd,NULL,pipefd[1],NULL,32768,SPLICE_F_MORE|SPLICE_F_MOVE); assert(ret!=-1); /*将管道的输出定向到connfd客户连接文件描述符*/ ret=splice(pipefd[0],NULL,connfd,NULL,32768,SPLICE_F_MORE|SPLICE_F_MOVE);
我们通过splice函数将客户端的内容读入到pipefd[1]中,然后再使用 splice函数从pipefd[0]中读出该内容到客户端,从而实现了简单高效的回射服务。整个过程未执行recv/send操作,因此也未涉及用户空间和内核空间之间的数据拷贝。
13.tee函数
tee函数在两个管道文件描述符之间复制数据,也是零拷贝操作。它不消耗数据,因此源文件描述符上的数据仍然可以用于后续的读操作。
#include<fcntl.h> ssize_t tee(int fd_in,int fd_out,size_t len,unsigned int flags);
- 该函数的参数的含义与splice相同(但fd_in和fd_out必须都是管道文件描述符)
- tee函数成功时返回在两个文件描述符之间复制的数据数量
- 返回0表示没有复制任何数据。tee失败时返回-1并设置errno。
利用tee函数和splice函数,实现了Linux下tee程序 (同时输出数据到终端和文件的程序
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<assert.h> 2 #include<stdio.h> 3 #include<unistd.h> 4 #include<errno.h> 5 #include<string.h> 6 #include<fcntl.h> 7 int main(int argc,char*argv[]) 8 { 9 if(argc!=2) 10 { 11 printf("usage:%s<file>\n",argv[0]); 12 return 1; 13 } 14 int filefd=open(argv[1],O_CREAT|O_WRONLY|O_TRUNC,0666); 15 assert(filefd>0); 16 int pipefd_stdout[2]; 17 int ret=pipe(pipefd_stdout); 18 assert(ret!=-1); 19 int pipefd_file[2]; 20 ret=pipe(pipefd_file); 21 assert(ret!=-1); 22 /*将标准输入内容输入管道pipefd_stdout*/ 23 ret=splice(STDIN_FILENO,NULL,pipefd_stdout[1],NULL,32768,SPLICE_F_MORE|SPLICE 24 assert(ret!=-1); 25 /*将管道pipefd_stdout的输出复制到管道pipefd_file的输入端*/ 26 ret=tee(pipefd_stdout[0],pipefd_file[1],32768,SPLICE_F_NONBLOCK); 27 assert(ret!=-1); 28 /*将管道pipefd_file的输出定向到文件描述符filefd上,从而将标准输入的内容写入 29 文件*/ 30 ret=splice(pipefd_file[0],NULL,filefd,NULL,32768,SPLICE_F_MORE|SPLICE_F_MOVE) 31 assert(ret!=-1); 32 /*将管道pipefd_stdout的输出定向到标准输出,其内容和写入文件的内容完全一致*/ 33 ret=splice(pipefd_stdout[0],NULL,STDOUT_FILENO,NULL,32768,SPLICE_F_MORE|SPLIC 34 assert(ret!=-1); 35 close(filefd); 36 close(pipefd_stdout[0]); 37 close(pipefd_stdout[1]); 38 close(pipefd_file[0]); 39 close(pipefd_file[1]); 40 return 0; 41 }
13.fcntl函数
- fcntl函数提供了对文件描述符的各种控制操作
- 另外一个常见的控制文件描述符属性和行为的系统调用是ioctl (fcntl函数是由POSIX规范指定的首选
#include<fcntl.h> int fcntl(int fd,int cmd,...);
- fd参数是被操作的文件描述符
- cmd参数指定执行何种类型的操作。
- 根据操作类型的不同,该函数可能还需要第三个可选参数arg。
在网络编程中,fcntl函数通常用来将一个文件描述符设置为非阻塞
int setnonblocking(int fd) { int old_option=fcntl(fd,F_GETFL);/*获取文件描述符旧的状态标志*/ int new_option=old_option|O_NONBLOCK;/*设置非阻塞标志*/ fcntl(fd,F_SETFL,new_option); return old_option;/*返回文件描述符旧的状态标志,以便*/ /*日后恢复该状态标志*/ }