记一次echo server出现的问题

1. 我做了什么

最近在学习如何用select函数实现echo server。期间遇到了一个关于缓冲区的问题,在这里分享给大家。

在使用read/recv, write/send类函数进行数据传输时,需要程序员手动创建缓冲区。通常(各种书籍中),大家都会将缓冲区的大小设置为1024或其整数倍。但是我在编写echo server时就遇到了一些问题。以下是echo server的图示。缓冲区大小是BUFFLEN=1024。

客户端这里write的长度是strlen(buffer),read的长度是BUFFLEN-1,这块我是参考《TCP/IP网络编程》这本书的。因为随后还有一个buffer[BUFFLEN] = ‘\0’ 的操作,所以read的长度是BUFFLEN-1(为了凑成一个字符串)。(谁能知道就是这里出了问题)。同时,服务端这里write和read的长度都是BUFFLEN。

2. 出现了什么问题

事情是这样的,当我开心参考着书上的代码,在电脑上敲了一遍,一顿编译之后,发现只有第一次能够echo成功,后续客户端的输入并不能被有效的echo回客户端,如下图所示。

客户端:

服务端:

我们可以看到服务端这块的读写还是正常的,但是客户端在第二次的read中,仅仅读了1个字节。我查阅了书中相关的内容,发现我的服务端代码和书上稍有不同。

//服务端代码
char buffer[BUFFLEN];
memset(buffer, 0, BUFFLEN);
int strlen = read(i, buffer, BUFFLEN);
printf("server read: %s, [%d]bytes\n",
buffer, strlen);
if (strlen == 0) {
    FD_CLR(i, &rdset);
    close(i);
} else {
//不同的地方:
//int wlen = write(i, buffer, strlen); 原书的代码
int wlen = write(i, buffer, BUFFLEN);
buffer[strlen] = '\0';
if (wlen < 0) {
    err_exit("write error");
}

printf(“server write: %s, [%d]bytes\n”,
buffer, wlen);

我很奇怪为什么仅仅write的长度不同就会导致这么严重的问题。通过查阅write, read的手册,还有抓包,我也没有找到问题的根源在哪里,唯一可以确定的是服务端应该是没有问题的,因为通过wireshark,我发现正常情况下的服务端和异常情况下的服务端的tcp报文的数量和顺序都是相同的。尝试了一些方案,比如 每次I/O前memset清空用户态缓冲区等等都没什么用。这个问题持续了有一天,周一早上我想着会不会是write和read操作的缓冲区长度不一致所导致的。

[图挂了]

服务端write

[图挂了]

客户端read

我尝试修改客户端的read读取的字节数为BUFFLEN竟发现这个问题被解决了。果然就是我预想的那样!!!

修改后的read

之所以会出现这个问题,是因为内核协议栈(或者是page cache?这个还需要进一步探讨)在客户和服务两端都存在相应的内核缓冲区,服务端会write到客户端的buffer中,而客户端的read会清空相应大小的缓冲区内容。试想如果服务端写入了1024字节,但是客户端只读取1023个字节,则此次操作缓存区内会剩余一个字节内容。下一次客户端的read就会将这一字节读到用户态缓冲中。

在客户端的输出中会出现”recv: 1 byte”这样的内容就是这个原因。

那么如何避免这种情况的出现呢?很明显,read/write, send/recv这些都是配对的操作。程序员要保证的就是write写入到内核缓冲区的内容必须能够被匹配的read读取完,不要在缓冲区中遗留陈旧的数据。

3. 遗留问题

肯定不会是我申请的用户缓冲区的问题,到底是那块的缓冲区出现问题,我也不太清楚。

4. 参考

[1]《TCP/IP网络编程》

Original: https://www.cnblogs.com/dennis-wong/p/12121767.html
Author: 成蹊0xc000
Title: 记一次echo server出现的问题

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/582792/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Ubuntu 20.04 双系统安装完整教程

    1、查看电脑的信息 1.1 查看BIOS模式 “win+r”快捷键进入”运行”,输入”msinfo32″回车…

    Linux 2023年6月7日
    091
  • python 练习题:接收一个或多个数并计算乘积

    以下函数允许计算两个数的乘积,请稍加改造,变成可接收一个或多个数并计算乘积 def product(x, y): return x * y python;gutter:true; …

    Linux 2023年6月8日
    095
  • 虚拟机网络地址配置你不知道的事儿-服务器的种类

    想必大家在初学Linux过程中,应该都是跟我一样白嫖一台虚拟机进行使用把,但是在大家白嫖的同时知不知道我们公司内是使用的什么样的服务器呢?公司肯定不会跟我们一样在自己电脑进行安装虚…

    Linux 2023年6月14日
    0125
  • LinuxKernel(一)

    首先,回顾一下基础的宏操作: C语言宏 # 与 ## #的作用是字符串化:在一个宏中的参数前面使用一个#,预处理器会把这个参数转换为一个字符数组 #define ERROR_LOG…

    Linux 2023年6月8日
    0109
  • samba服务设置与访问共享文件夹

    samba服务设置与访问共享文件夹 linux设置文件夹共享 windows连接共享文件夹(运行->//IP/route) linux连接共享文件夹 1、基本服务安装与配置 …

    Linux 2023年6月14日
    088
  • SQLI-LABS(Less-8)

    Less-8(GET-Blind-Boolean Based-Single Quotes) 打开 Less-8页面,可以看到页面中间有一句 Please input the ID …

    Linux 2023年6月6日
    086
  • Bash shell

    例一: 函数、返回状态值、比较 #!/bin/bash NUM=$(date +%S) echo "当前苹果价格是每斤$NUM元" echo "===…

    Linux 2023年5月28日
    082
  • 逆波兰表达式

    运用lambda表达式和包装器 150. 逆波兰表达式求值 – 力扣(LeetCode) class Solution { public: int evalRPN(ve…

    Linux 2023年6月13日
    0109
  • Jmeter 使用Json提取请求数据

    使用Json提取器可以提取请求响应数据 Json提取器 位置: 后置处理器-》Json提取器 使用介绍 1,变量名 变量名,其他部分引用方式: ${变量名}若提取多个变量,多个之间…

    Linux 2023年6月8日
    089
  • Redis 主从复制

    Redis主从复制的原理 当建立主从关系时,slave配置slaveof 当redis生成dump.rdb文件时,工作过程如下 redis主进程fork一个子进程 fork出来的子…

    Linux 2023年5月28日
    089
  • Linux 下安装 node.js

    这里介绍两种安装方式: 编译安装和使用编译后的安装包安装。 安装目录: /usr/local 一、使用编译安装包安装 1、进入安装目录: 2、下载安装包: 3、解压: 4、进入解压…

    Linux 2023年6月13日
    092
  • js笔记之while循环

    while循环就是for循环去掉前后两个条件 var i = 0; for( ; i < 10; ){ document.write(i); document.write(&…

    Linux 2023年6月13日
    098
  • 04-MySQL锁

    数据库锁 1、SQL语言包括那几个部分 SQL语言包括 数据定义(DDL)、数据操纵(DML)、数据控制(DCL)和数据查询(DQL)四个部分 2、每部分都有哪些操作关键词 数据定…

    Linux 2023年6月7日
    0142
  • Linux-系统启动与MBR扇区修复

    1.系统启动过程 1.1 MBR扇区 1.2 MBR扇区的备份与还原 1.3 修复MBR 1.3.1 dd备份MBR信息 1.3.2 光驱启动修复 1.4 grub故障修复 1.系…

    Linux 2023年5月27日
    0123
  • 关于网络安全防护架构中的DMZ区

    公司有一个网站群的业务,应用规模比较大,目前计划是从传统的虚拟机部署方式迁移到内部的私有云。 这种迁移的动作是一个很好的学习机会。在交流的时候的时候,领导有提到现有的架构基本上是参…

    Linux 2023年6月14日
    0101
  • [20220811]奇怪的隐式转换问题(12c补充测试).txt

    [20220811]奇怪的隐式转换问题(12c补充测试).txt –//生产系统遇到一个奇怪的隐式转换问题,问题在于没有发生隐式转换,前面已经做了一些分析增加12c下的…

    Linux 2023年6月13日
    080
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球