zoukankan      html  css  js  c++  java
  • 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
      ");
              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
    ",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
    ",errno);
        } else{
            char header_buf[BUFFER_SIZE];
            memset(header_buf,'', 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,'
    ',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
    ","HTTP/1.1",status_line[0]);
                len+=ret;
                ret = snprintf(header_buf+len,BUFFER_SIZE-1-len,"Content-Length:%d
    ",file_stat.st_size);
                len+=ret;
                ret = snprintf(header_buf+len,BUFFER_SIZE-len-1,"%s","
    ");
                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
    ","HTTP/1.1",status_line[1]);
                len+=ret;
                ret = snprintf(header_buf+len,BUFFER_SIZE-1-len,"%s","
    ");
                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 
    ", 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 个字符到目标串中,然后再在后面加一个 ''。所以如果目标串的大小为 n 的话,将不会溢出。

    #include <stdio.h>
     
    int main(int argc, char **argv)
    {
        char str[10] = {0};
        snprintf(str, sizeof(str), "0123456789012345678");
        printf("str=%s
    ", 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
    ", 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
    ",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
     ", 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>
    ",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;/*返回文件描述符旧的状态标志,以便*/
    /*日后恢复该状态标志*/
    }
  • 相关阅读:
    软件RAID 0
    逻辑卷管理lvm
    磁盘配额quota
    合并 CentOS 6.8 的两个ISO镜像
    挂载mount
    非交互式添加分区
    磁盘分区-gdisk用法
    C博客作业01--分支、顺序结构
    C语言--第0次作业
    浅议正则表达式
  • 原文地址:https://www.cnblogs.com/jingchu/p/10016575.html
Copyright © 2011-2022 走看看