ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

套接字的读写操作在阻塞、非阻塞模式下的表现

2021-08-23 23:33:43  阅读:222  来源: 互联网

标签:const 读取 字节数 读写操作 read 阻塞 接字


背景

  1. 了解套接字的读写操作在阻塞模式、非阻塞模式下的表现会有差异,但是不知道read()write()操作套接字时具体的效果;
  2. read()想要读取的数据字节数并不一定等于实际读取到的字节数,如何使读操作实际读取的字节数与想要获取的字节数一样?write()类同。

读写操作什么情况下会被阻塞?

  1. 读(read):读套接字是将套接字接收缓存区中数据读取到应用层中,如果此时接收缓存区中为空、没有待读取的数据,读操作将被阻塞;
  2. 写(write):同理,写套接字是将应用层中数据写到套接字发送缓存区中,如果此时发送缓存区中剩余空间大小为0、没有可写空间,写操作将被阻塞。

套接字设置为阻塞/非阻塞模式下,read()/write()表现差异

image-20210822165105215

除上之外,read()write()有一重要区别需要注意,阻塞模式下:

  • 接收缓存区中有数据,read()将数据读取至应用层,即使缓存数据长度小于想要获取长度read()也在读取后返回;
  • write()将发送缓存区中剩余空间写完后,仍有待写入数据没有写完,它将继续等待直到将所有数据写入发送缓存区中。

嗯,read()在努力,write()在尽力。

实用的读/写函数

/**@brief: 从套接字读取n个字节数据
* @param[i]: const int sockFd, 套接字ID
* @param[i]: const int n, 待读取字节数
* @param[o]: char *pBuf, 数据缓存区
* @return: 返回成功读取的字节数,失败返回-1
*/
size_t readn(char *pBuf, const int sockFd, const size_t n)
{
  size_t nLeft = n; // 剩余待读取的字节数
  ssize_t nRead = 0; // 当前此读取的字节数

  if (NULL == pBuf || sockFd < 0 || n <= 0)
  {
    CLIENT_MAIN_DEBUG(ERROR, "readn, param is invalid.\n");
    return FAILURE;
  }

  while (nLeft > 0)
  {
    nRead = read(sockFd, pBuf, nLeft);
    if (nRead < 0) // 读取异常处理
    {
      if (EINTR == errno) // 中断异常,重新读取
      {
        CLIENT_MAIN_DEBUG(DEBUG, "read is interrupted by others.\n");
        continue;
      }
      else
      {
        CLIENT_MAIN_DEBUG(ERROR, "read failed, %s.\n", strerror(errno));
        return FAILURE;
      }
    }
    else if (0 == nRead) // 读取到文件结束符(FIN)
    {
      CLIENT_MAIN_DEBUG(DEBUG, "read the end of file.\n");
      return (n - nLeft);
    }
    else
    {
      nLeft -= nRead;
      pBuf += nRead;
    }
  }

  return n;
}
/**@brief: 向套接字写n个字节数据
* @param[i]: const int sockFd, 套接字ID
* @param[i]: const int n, 待读取字节数
* @param[i]: const char *pBuf, 数据缓存区
* @return: 返回成功写入的字节数,失败返回-1
*/
size_t writen(const int sockFd, const size_t n, const char *pBuf)
{
  size_t nLeft = n; // 剩余待写入的字节数
  ssize_t nWrite = 0; // 当前写入的字节数

  if (sockFd < 0 || n <= 0 || NULL == pBuf)
  {
    CLIENT_MAIN_DEBUG(ERROR, "writen, param is invalid.\n");
    return FAILURE;
  }

  while (nLeft > 0)
  {
    nWrite = write(sockFd, pBuf, nLeft);
    if (nWrite <= 0) // 写入异常处理
    {
      if (EINTR == errno) // 中断异常,重新写入
      {
        CLIENT_MAIN_DEBUG(DEBUG, "write is interrupted by others.\n");
        continue;
      }
      else
      {
        CLIENT_MAIN_DEBUG(ERROR, "write failed, %s.\n", strerror(errno));
        return FAILURE;
      }
    }
    else
    {
      nLeft -= nWrite;
      pBuf += nWrite;
    }
  }

  return n;
}

为什么读写操作时,套接字一般被设置为阻塞模式、而不设置为非阻塞模式?

套接字为非阻塞模式时,读写操作被阻塞则直接返回,如果还想使read()/write()实际读写的数据与想要操作的数据相同,那么就需要更为复杂的异常处理逻辑。而对于单纯的读写套接字来说,非阻塞并没有带来其他的便利。综上来说,读写套接字时将其设置为非阻塞?大可不必

标签:const,读取,字节数,读写操作,read,阻塞,接字
来源: https://www.cnblogs.com/zpchya/p/15178169.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有