zoukankan      html  css  js  c++  java
  • socket数据收发

    socket读写

    TCP协议是面向流的,read和write调用的返回值往往小于参数指定的字节数。对于read调用,如果接收缓冲区中有20字节,请求读100个字节,就会返回20。对于write调用,如果请求写100个字节,而发送缓冲区中只有20个字节的空闲位置,那么write会阻塞,直到把100个字节全部交给发送缓冲区才返回。但如果socket文件描述符中有O_NONBLOCK标志,则write不阻塞,直接返回20。

    为避免这些情况干扰主程序逻辑,确保读写所请求的字节数,应包装read和write函数。

    当设置socket为非阻塞模式时,要用select()或epoll()判断什么时候可正常写入或读出。

    • write

    sszie_t write(int fd, const void *buf, size_t count);

    return:成功,返回写入的字节数;失败-1。

    在网络程序中,当我们向socket写时有两种可能:

    1. write的返回值大于0,表示写了部分或者全部的数据。
    2. 返回值小于0,此时出现了错误。我们要根据错误类型来处理。如果错误为EINTR表示在写的时候出现了中断错误,应重试。如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接,返回-1)。
    3. 此外还有可能socket为非阻塞(O_NONBLOCK),当缓冲区满时,立即返回0。(我的想法) ----错误想法,fd设置为非阻塞时,不能写立即返回-1,设置errno为EAGAIN或EWOULDBLOCK(man write ERRORS)。
    4. 返回0时,表示未写数据,继续写即可。

    int my_write(int fd, void *buffer, int len){

      int bytes_left;

      int written_bytes;

      char *ptr;

      ptr = buffer;

      bytes_left = len;

      while(bytes_left > 0){

        written_bytes = write(fd, ptr, bytes_left);

        if(writte_bytes <= 0){   //出错了

          if(errno == EINTR && written_bytes < 0)    // 中断错误,继续写。

            writen_bytes = 0;

          else         //其他错误,直接退出

            return -1;                    

        }

    bytes_left -= writen_bytes;
    
    
    ptr += written_bytes;
    }

    return len;

    }

    • read

    ssize_t read(int fd, void *buf, size_t count);

    return:成功,返回读取到的字节数;失败-1。

    返回值为0,表示已经读到文件的结束;返回值小于0 表示出现了错误。如果错误为EINTR说明读是由中断引起的(继续读),如果是ECONNREST表示网络连接出了问题。

    read()阻塞时,一直等,等于0表示文件结束或网络连接关闭;read()非阻塞,无数据可读时立即返回-1,errno为EAGAIN(若一直读,一直返回-1,errno为EAGAIN)。

    int my_read(int fd,void *buffer,int length){

      int bytes_left;

      int bytes_read;

      char *ptr;

      bytes_left=length;

      while(bytes_left>0){

        bytes_read=read(fd,ptr,bytes_left);

        if(bytes_read<0){

          if(errno==EINTR)          // 中断引起的,继续读

            bytes_read=0;

          else

            return(-1);          //其他原因,直接退出

        }

        else if(bytes_read==0)     // 对方close连接(收到FIN包)

          break;

        bytes_left-=bytes_read;

        ptr+=bytes_read;

      }

    return(length-bytes_left);

    }

    • recvfrom

    int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr * from, int *fromlen);

    • sendto

    int sendto(int sockfd, const void *msg, int len, unsigned int flags, struct sockaddr *to, int tolen);

    注:如果对信息的来源不感兴趣,可以将from和fromlen设置为NULL。

  • 相关阅读:
    ubutun Sogou输入法安装
    git的使用
    比较字符串(包含以及变位词)
    python 与时间有关的操作
    PyBrain库的example之NFQ流程图分析
    python之面向对象(继承)
    C/C++中一些不太注意到的小知识点--[锦集]
    python 有关引用的一些问题
    CMake尝鲜
    vim初探
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/4986192.html
Copyright © 2011-2022 走看看