Tcp/Ip I/O函数

  • 用于创建文件描述符的函数,包括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;
    
    
    }
    View Code

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

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


}
View Code

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。 

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



}
View Code

 

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程序 (同时输出数据到终端和文件的程序

 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 }
View Code

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;/*返回文件描述符旧的状态标志,以便*/
/*日后恢复该状态标志*/
}

 

转载于:https://www.cnblogs.com/jingchu/p/10016575.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值