• 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。

  • 相关阅读:
    linux内核中GNU C和标准C的区别
    linux内核中GNU C和标准C的区别
    Getting start with dbus in systemd (02)
    Getting start with dbus in systemd (01)
    Getting start with dbus in systemd (03)
    物理内存相关的三个数据结构
    数据类型对应字节数(32位,64位 int 占字节数)
    Linux kernel 内存
    共模电感的原理以及使用情况
    [原创]DC-DC输出端加电压会烧毁
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/4986192.html
Copyright © 2020-2023  润新知