zoukankan      html  css  js  c++  java
  • linux网络编程之IO函数

    Linux操作系统中的IO函数主要有read(),write(),recv(),send(),recvmsg(),sendmsg(),readv(),writev().

    接收数据的recv()函数

    #include<sys/types.h>

    #include<sys/socket.h>

    ssize_t recv(int s,void *buf,size_t len,int flags);

    该函数从套接字s中接收数据放到缓冲区buf中,buf的长度是len,操作的方式由flags指定。因此,第一个参数s是套接口文件描述符,它是由系统调用socket()返回的,第二个参数buf是一个指针,指向接收网络数据的缓冲区,第三个参数len以字节为单位来表示缓冲区的大小,第四个参数flags用于设置接收数据的方式,其值和含义如下:

    MSG_DONOTWAIT 非阻塞操作,立刻返回,不等待

    MSG_ERRQUEUE 错误消息从套接字错误队列接收

    MSG_OOB 接收带外数据,而不是接收一般数据

    MSG_PEEK 查看数据,不进行数据缓冲区的清空

    MSG_TRUNC 返回所有的数据,此时如果用户的缓冲区太小,那么数据将被截断。仅仅复制缓冲区大小的数据,其他数据会被丢失

    MSG_WAITALL 等待所有消息,它告诉内核在没有读到请求的字节数之前不使读操作返回

    recv()函数从内核的接收缓冲区中复制数据到用户指定的缓冲区,当内核中的数据比指定的缓冲区小时,一般情况下,会复制缓冲区中的所有数据到用户缓冲区,并返回数据的度当内核缓冲区中的数据比用户指定的多时,会将用户指定长度len的接收缓冲区中的数据复制到用户指定地址,其余的数据需要下次调用接收函数的时候再复制,内核在复制用户指定的数据之后,会销毁已经复制完毕的数据并进行调整。recv()函数通常用于TCP类型的套接字,UDP使用recvfrom()函数接收数据,不过,如果你的UDP也绑定了地址和端口,那么也可以使用recv()函数接收数据。

    recv()函数的返回值是成功接收到的字节数,当返回值为-1时错误发生。可以通过查看errno获取错误码,查看错误信息。

    发送数据的send()函数

    #include<sys/types.h>

    #include<sys/socket.h>

    ssize_t send(int s,const void *buf,size_t len,int flags);

    与recv()函数相反过来,send()函数将缓冲区buf中大小为len的数据,通过套接字文件描述符按照flags指定的方式发送出去,其中的参数含义与recv()函数中一致,它的返回值是成功发送的字节数。当send()函数返回值小于len时,表明缓冲区中还有部分数据没有成功发送,这时需要重新发送剩余部分的数据,通常的剩余数据发送方法是对原来buf中的数据位置进行偏移,偏移的大小为已发送成功的字节数。函数send()发生错误的时候返回值为-1,这时可以通过查看errno获取错误码,而当另一方使用正常方式关闭连接的时候其返回值为0,例如通过调用close()函数关闭连接。

    函数send()只能用于套接字处于连接状态的描述符,之前必须用connect()函数或者其他函数进行连接。对于send()函数和write()函数之间的差别是表示发送方式的flag,当flag为0时。send()函数和write()函数完全一致,而且send(s,buf,len,flags)与sendto(s,buf,len,flags,NULL,0)是等价的。

    接收多个缓冲区数据的readv()函数

    #include<sys/uio.h>

    ssize_t readv(int s,const struct iovec *vector,int count);

    readv()函数可以用于接收多个缓冲区数据,它从套接字描述符s中读取count块数据放到缓冲区向量vector中。每个 iovec 描述了一块要传送的数据; 它开始于 iov_base (在用户空间)并且有 iov_len 字节长. count 参数告诉有多少 个iovec 结构. 这些结构由应用程序创建, 但是内核在调用驱动之前拷贝它们到内核空间.参数vector是一个指向向量的指针,结构struct iovec在文件<sys/uio.h>中定义:

    struct iovec{

     void *iov_base;//向量缓冲区的地址

     size_t iov_len;//向量缓冲区的大小,以字节为单位

    };

    在调用readv()函数的时候必须指定iovec的iov_base的长度,将值放到成员iov_len中。

    发送多个缓冲区的writev()函数

    #include<sys/uio.h>

    ssize_t writev(int fd,const struct iovec *vector,int count);

    一个 readv 调用被期望来轮流读取指示的数量到每个缓存. 相反, writev 要收集每个缓存的内容到一起并且作为单个写操作送出它们.它的使用与readv()类似。

     

    下面的程序代码展示了如何使用writev函数将三个独立的C字符串作为一次写操作写入标准输出:

    #include 
    int main(int argc,char **argv)
    {
        static char part2[] = "apple apple";
        static char part3[]    = "computer";
        static char part1[] = "book book";
        struct iovec iov[3];
        iov[0].iov_base = part1;
        iov[0].iov_len = strlen(part1);
        iov[1].iov_base = part2;
        iov[1].iov_len = strlen(part2);
        iov[2].iov_base = part3;
        iov[2].iov_len = strlen(part3);
        writev(1,iov,3);
        return 0;
    }

    接收数据的recvmsg()函数

    #include<sys/types.h>

    #include<sys/socket.h>

    ssize_t recvmsg(int s,struct msghdr *msg,int flags);

    与recv()函数和readv()函数相比u,这个函数的使用要复杂一点,主要区别在于第二个参数,它使用了内核的一个结构体msghdr:

    struct msghdr {
        void         *msg_name;  msg_name成员指向我们要发送或是接收信息的套接口地址
        socklen_t    msg_namelen; msg_namelen指明了这个套接口地址的长度
        struct iovec *msg_iov; msg_iov成员指向一个struct iovec数组
        size_t       msg_iovlen;
        void         *msg_control; msg_control指向附属数据缓冲区
        size_t       msg_controllen; msg_controllen指明了缓冲区大小
        int          msg_flags;
    };

     

    #include<sys/uio.h>

    sszie_t sendmsg(int s,const struct msghdr *msg,int flags);

    sendmsg()函数用于发送数据,它的使用与recvmsg()函数类似,recvmsg与sendmsg功能更为强大,当然用起来也更为复杂。

    上述函数的比较:

    1.函数read()/write()和readv()/writev()可以对所有的文件描述符使用;recv()/send(),recvfrom()/writeto()和recvmsg()/sendmsg()只能操作套接字描述符。

    2.函数readv()/writev()和recvmsg()/sendmsg()可以操作多个缓冲区,read()/write(),recv()/send()和recvfrom()/sendto()只能操作单个缓冲区。

    3.函数recv()/send(),recvfrom()/sendto()和recvmsg()/sendmsg()具有可选标志。

    4.函数recvfrom()/sendto()和recvmsg()/sendmsg()可以选择对方的IP地址。

    5.函数recvmsg()/sendmsg()有可以选择的控制信息,能进行高级操作。

     

  • 相关阅读:
    phpcms后台进入地址(包含No permission resources错误)
    phpmyadmin上传大sql文件办法
    ubuntu彻底卸载mysql
    Hdoj 2602.Bone Collector 题解
    一篇看懂词向量
    Hdoj 1905.Pseudoprime numbers 题解
    The Python Challenge 谜题全解(持续更新)
    Hdoj 2289.Cup 题解
    Hdoj 2899.Strange fuction 题解
    Hdoj 2199.Can you solve this equation? 题解
  • 原文地址:https://www.cnblogs.com/kunhu/p/3623962.html
Copyright © 2011-2022 走看看