网络IPC, socket(4): 数据传输函数

来源:互联网 发布:java throws 编辑:程序博客网 时间:2024/06/05 18:07

    前面已经说过, 对文件的操作函数read/write也同样可以操作socket描述符, 就把socket描述符当作一个文件来处理. 所以在socket上使用read/write是有意义的, 可以传递socket描述符到那些本来设计为处理本地文件的函数, 还可以安排socket描述符到执行进程的子进程, 该子进程也不需要了解socket.

    虽然read/write可以执行socket上的数据传输, 但它不能指定选项, 不能从多个客户端接收数据, 也不能向多个客户端发送数据. 如果需要实现这些, 就需要使用socket提供的函数了.

 

1. 发送数据:

  • ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);
    • 使用时必须已经连接.
    • 参数buf, nbytes和write中的含义一致.
    • flags是socket的调用标志, 可以是:
      • MSG_DONTROUTE: 不走路由, 也就是说数据不可越出本地网络.
      • MSG_DONTWAIT: 非阻塞操作, 等价于write使用O_NONBLOCK.
      • MSG_EOR: 如果协议支持, 此为记录结束.
      • MSG_OOB: 如果协议支持, 发送带外数据.
    • send成功返回时, 仅仅表示数据已经准确无误地发送到了网络上, 而不关心接收端.

 

  • ssize_t sendto(int sockfd, const void *buf, size_t nbytes, int flags,

 const struct sockaddr *destaddr, socklen_t destlen);

    • destaddr指针指向目标地址的结构.
    • 其他同send.

 

  • ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
    • msghdr的结构定义如下:
      struct msghdr
      {
          
      void             *msg_name;         /* optional address */
          socklen_t    
      *msg_namelen;    /* address size in bytes */
          
      struct iovec *msg_iov;             /* array of I/O buffers */
          
      int                 msg_iovlen;        /* number of elements in array */
          
      void             *msg_control;      /* ancillary of data */
          socklen_t      msg_controllen; 
      /* number of ancillary bytes */
          
      int                  msg_flags;         /* flags for received message */
          .
          .
          .
      }
      ;
    • 该函数指定多重缓冲取传输数据, 类似于writev.

 

2. 接收数据:

  • ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);
    • flags可以是:
      • MSG_OOB: 如果协议支持, 接收带外数据.
      • MSG_PEEK: 返回报文内容而不真正取走报文.
      • MSG_TRUNC: 即使报文被截断, 返回的也是报文的实际长度.
      • MSG_WAITALL: 等待, 直到所有的数据可用(仅限SOCK_STREAM).

 

  • ssize_t recvfrom(int sockfd, void *restrict buf, size_t len, int flags,

                                             struct sockaddr *restrict addr, socklen_t *restrict addrlen);

 

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

 

3. 总结:

    函数sendto/recvfrom和函数send/recv很类似, 区别在于sendto/recvfrom允许在无连接的socket上指定一个目标地址.

  • 对于面向连接的socket, 目标地址是忽略的, 因为目标地址已经包含在连接中了.
  • 对于无连接的socket, 不能使用send/recv, 除非在调用connect时预先设定了目标地址. 否则, 需要使用sendto/recvfrom来完成报文的传输.

    这里介绍了数据传输的所有函数, 在socket系列文章的后面会有实例来调用这些函数.