我们只关心代码中的业务逻辑和底层阻塞原因

客户端代码

发送数据

  std::string message(len, 'S');
int nw = stream->sendAll(message.c_str(), message.size());
printf("sent %d bytes\n", nw);

接受服务端回显的数据

  std::vector<char> receive(len);
int nr = stream->receiveAll(receive.data(), receive.size());
printf("received %d bytes\n", nr);

服务端代码

采用thread per connection 模型,每个链接分配一个线程来进行数据回显

  InetAddress listenAddr(3007);
Acceptor acceptor(listenAddr);
printf("Accepting... Ctrl-C to exit\n");
int count = 0;
bool nodelay = argc > 1 && strcmp(argv[1], "-D") == 0;
while (true)
{
TcpStreamPtr tcpStream = acceptor.accept();
printf("accepted no. %d client\n", ++count);
if (nodelay)
tcpStream->setTcpNoDelay(true);
// C++11 doesn't allow capturing unique_ptr in lambda, C++14 allows.
std::thread thr([count] (TcpStreamPtr stream) {
printf("thread for no. %d client started.\n", count);
char buf[4096];
int nr = 0;
while ( (nr = stream->receiveSome(buf, sizeof(buf))) > 0)
{
int nw = stream->sendAll(buf, nr);
if (nw < nr)
{
break;
}
}
printf("thread for no. %d client ended.\n", count);
}, std::move(tcpStream));
thr.detach();

发送数据过大时,客户端阻塞的原因分析



在发送数据过大时,客户端会陷入长时间的阻塞状态,发送队列和接受队列的状态如上图,分析代码中的业务逻辑可知,由于客户端在发送完所有数据之后才会接受,在发送的时候将数据放入内核缓冲区,内核缓冲区长度固定,服务端是边读取边发送,所以服务端在向客户端发送回显数据时可能会将发送内核缓冲区填满(此时客户端没有发送完所有元素不会开始读,这样两边都在等待。。。)

解决方式 header + payload 方式进行数据交互

  • 从应用层协议解决这个问题

    每次发送数据之前进行分包,让接收方准备好对应的内存空间后进行接受,具体应用实例

阻塞IO下的echo回显实验的更多相关文章

  1. Node.js IO处理输入和回显,以及当今web应用程序的发展史

    1.关于Node.js IO处理输入和回显 在Windows终端或者CD中输入   echo  'I must learn about Node.js' 结果将刚刚输入的   echo  'I mus ...

  2. JS 实现下拉框回显

    JS 实现下拉框回显 学习内容: 需求 总结: 学习内容: 需求 用 JS 实现下拉框回显 实现代码 <!DOCTYPE html> <html lang="en" ...

  3. Layui:select下拉框回显

    一..需求场景分析 基于Thymeleaf模板下的layui下选框回显. 二.获得一个Layui标配的下拉框,我们需要在html中填写的内容如下 <div class="layui-f ...

  4. linux c下输入密码不回显

    今天做一个登录程序,需要屏蔽掉密码,于是自己就在网上找资料,找到了一种和linux终端下输入密码方式相同的方法,不显示在终端,具体代码实现如下. #include<stdio.h> #in ...

  5. vue 运用ElementUI,做select下拉框回显

    第一.加载的顺序,应该先加载下拉框要选择的数据,然后在通过编辑查询数据后回显. 第二.要保证select下拉的ID和v-model里边的id保持一致. 第三.elementUI就会自动的将数据回显了. ...

  6. 关于一个socket在阻塞模式下是否还可以使用的实验

    想到一个socket在多线程模式下,是否可以同时使用的问题,比如socket A阻塞在recv,而别的线程用socket A send是否能成功,下面上实验代码 void thread_socket( ...

  7. linux下输入密码不回显

    这几天在做一个登陆的程序,需要将输入的密码屏蔽掉,自己百度,找到了两种方法,先贴下第一种方法, #include<stdio.h> #include<unistd.h> int ...

  8. thymeleaf单选回显,多选回显,选回显,下拉默认选中第一个

    //默认选中第一个<input type ="radio" name="repaymentType" th:each ="repaymentTy ...

  9. SpEL表达式注入漏洞学习和回显poc研究

    目录 前言 环境 基础学习和回显实验 语法基础 回显实验 BufferedReader Scanner SpEL漏洞复现 低版本SpringBoot中IllegalStateException CVE ...

随机推荐

  1. What is the difference between try/except and assert?

    assert only check if a condition is true or not and throw an exception. A try/except block can run a ...

  2. POJ 2255 Tree Recovery——二叉树的前序遍历、后序遍历、中序遍历规则(递归)

    1.前序遍历的规则:(根左右) (1)访问根节点 (2)前序遍历左子树 (3)前序遍历右子树 对于图中二叉树,前序遍历结果:ABDECF 2.中序遍历的规则:(左根右) (1)中序遍历左子树 (2)访 ...

  3. 1008: ASCII码

    题目描述 相信大家一定都知道大名鼎鼎的ASCII码,这次给你的任务是输入数字(表示ASCII码),输出相对应的字符信息. 输入 第一行为一个整数T(1<=T<=1000).接下来包括T个正 ...

  4. 嵌入式之:Linux下文件编译过程

    本文主要三个部分:1.GNU GCC简介 2.C/C++交叉编译器arm-elf-gcc 3.make文件,用于工程管理 部分一:GNU GCC简介: 该编译器基本功能: (1)输出预处理后的文件(展 ...

  5. perl学习之:匹配修饰符/s /m

    m 是将字符串作为多行处理,s是将字符串作为单行处理,如果是s在字符串中出现的\n就相当于普通字符. 6.6. Matching Within Multiple Lines6.6.1. Problem ...

  6. 看外设(uart/spis/i2c/i2s)模块设计

    1.先看外设接口协议. 2.看具体设计文档. 3.仿真case.

  7. 排序算法C语言实现——快速排序的递归和非递归实现

    /*快排 -  递归实现nlogn*//*原理:    快速排序(Quicksort)是对冒泡排序的一种改进.    快速排序由C. A. R. Hoare在1962年提出.它的基本思想是:通过一趟排 ...

  8. eclipse错误日志

    一.普通错误:(必现) 1.空指针: 2. 数组下标溢出,越界 3. 数组下标定义为双精度不妥,应该是整数 4. 类型转换错误(与手机分辨率有关) 二.  数据库错误:(必现) 1. 数据库,报错(数 ...

  9. 【机房收费系统 4】:VB获取标准北京时间,免除时间误差

    导读:这又是师傅给我指出的一个问题,说实话,其实开始根本没有当回事,觉得麻烦,可是,等我完成了获取标准北京时间后,我发现,这一步,是必须的.谢谢师傅对我的严格要求,让我一步一步的成长起来! 一.事件缘 ...

  10. .NET重构(四):窗体继承+模板方法,完美实现组合查询

    导读:在机房重构中,有好些个查询都是大同小异,最为显著的就是组合查询了.怎样给自己省事儿,相同的东西能不能重复利用,就成了一个现实的问题.第一遍做机房的时候,使用的更多的是:复制+粘贴.学习了设计模式 ...