1 LISTEN状态:表示队列中的连接数量,非LISTEN状态为字节数量;

非 LISTEN 状态

  • Recv-Q 表示 receive queue 中的 bytes 数量;
  • Send-Q 表示 send queue 中的 bytes 数值。

2 Recv-Q  正在等待accept的连接数,Send-Q表示全连接队列容量

表示的当前等待服务端调用 accept 来三次握手的 listen backlog 数值,即图中的全连接队列值(最大值为Send_Q+1),当客户端通过connect() 去连接正在 listen() 的服务端时,这些连接会经过半连接队列,接收到ACK后,进入accept queue(全连接队列) ,在里面等待直到被服务端 accept();

Send-Q 表示的则是最大的 listen backlog 数值,这就是 min(backlog, /proc/sys/net/core/somaxconn)的值

3 详细过程如下图

4 我们实际操作下:观察Recv-Q 的变化

启动服务端执行命令:(注意:连接事件发生后|accept操作执行前会睡眠Thread.sleep(100000);)

使用NIO作为服务端监听TCP端口:9779

~/recv_q_send_q# /usr/bin/java NIOServer
NOIServer start run in port 9779

可以看到默认Send-Q值为50;

如果并发请求的链接数超多50,多余的怎样?感兴趣的可以自己修改代码测试mark

如果等待时间过长客户端也会收到服务端的拒绝反馈,正常情况下如果超出的连接数多不并且等待时间不多,可以得到服务端的正常响应

启动客户端执行命令:

/usr/bin/java NIOClient

等待100秒后:

5 这就解释了Recv-Q 在服务端debug时为啥会阻断后面的链接接入,因为全连接队列满了,后面的链接只能等待

参考NIO代码:

server端import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;public class NIOServer {private int num;private static final int BLOCK = 4096;private static final ByteBuffer sendB = ByteBuffer.allocate(BLOCK);private static final ByteBuffer receB = ByteBuffer.allocate(BLOCK);private Selector selector;public NIOServer(int port) throws IOException {//开启ServerSocketChannelServerSocketChannel serverSocketChannel = ServerSocketChannel.open();//设置为非阻塞serverSocketChannel.configureBlocking(false);//获取ServerSocketServerSocket serverSocket = serverSocketChannel.socket();//绑定ServerSocket提供服务的端口serverSocket.bind(new InetSocketAddress(port));//开启选择器selector = Selector.open();//将ServerSocketChannel注册到选择器上serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("NOIServer start run in port " + port);}/*** 监听选择器的数据** @throws IOException*/private void listen() throws IOException {//循环监听,事件驱动模式while (true) {//select()阻塞,等待有事件发生时唤醒selector.select();Set<SelectionKey> selectionKeys = selector.selectedKeys();Iterator<SelectionKey> iterator = selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey selectionKey = iterator.next();//处理完后移除该事件iterator.remove();//处理该事件handleKey(selectionKey);}}}/*** 处理选择器的监听事件** @param selectionKey 选择器的监听事件key* @throws IOException*/private void handleKey(SelectionKey selectionKey) throws IOException {ServerSocketChannel serverSocketChannel = null;SocketChannel socketChannel = null;int count = 0;//客户端新连接if (selectionKey.isAcceptable()) {//开启通道连接serverSocketChannel = (ServerSocketChannel) selectionKey.channel();try {System.out.println(System.currentTimeMillis() + "收到请求我在睡眠100秒...");Thread.sleep(100000);} catch (InterruptedException e) {e.printStackTrace();}socketChannel = serverSocketChannel.accept();System.out.println(System.currentTimeMillis() + "accept...");//设置为非阻塞socketChannel.configureBlocking(false);//将通道注册到选择器socketChannel.register(selector, SelectionKey.OP_READ);} else if (selectionKey.isReadable()) {//获取读事件通道socketChannel = (SocketChannel) selectionKey.channel();//清除原先读缓存receB.clear();//读取通道缓存count = socketChannel.read(receB);if (count > 0) {//解析通道缓存数据String receMsg = new String(receB.array(), 0, count);System.out.println("receive from client " + receMsg);//注册切到写事件socketChannel.register(selector, SelectionKey.OP_WRITE);}} else if (selectionKey.isWritable()) {//获取写事件通道socketChannel = (SocketChannel) selectionKey.channel();//清除发送缓存数据sendB.clear();String sendMsg = "num " + num++;//设置待发送的数据sendB.put(sendMsg.getBytes());//准备写sendB.flip();int write = socketChannel.write(sendB);System.out.println("send to client " + sendMsg);//注册切到读事件socketChannel.register(selector, SelectionKey.OP_READ);}}public static void main(String[] args) throws Exception {new NIOServer(9779).listen();}
}
客户端代码:import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;public class NIOClient {private static final int BLOCK = 4096;private static final ByteBuffer sendB = ByteBuffer.allocate(BLOCK);private static final ByteBuffer receB = ByteBuffer.allocate(BLOCK);private SocketChannel socketChannel;private Selector selector;public NIOClient(String ip, int port) throws IOException {//开启通道socketChannel = SocketChannel.open();//设置为非阻塞socketChannel.configureBlocking(false);//开启选择器selector = Selector.open();//将通道注册到选择器socketChannel.register(selector, SelectionKey.OP_CONNECT);//连接服务端socketChannel.connect(new InetSocketAddress(ip, port));}/*** 连接服务器*/public void connect() throws IOException {Set<SelectionKey> selectionKeys;Iterator<SelectionKey> iterator;SelectionKey selectionKey;int index = 0;while (true && index < 1000) {index++;selector.select();selectionKeys = selector.selectedKeys();iterator = selectionKeys.iterator();while (iterator.hasNext()) {selectionKey = iterator.next();handleKey(selectionKey, index);}selectionKeys.clear();}//交互10次后关闭连接socketChannel.close();}/*** 处理选择器监听事件** @param selectionKey*/public void handleKey(SelectionKey selectionKey, int index) throws IOException {SocketChannel client;int count = 0;// 连接事件if (selectionKey.isConnectable()) {System.out.println("client connect......");client = (SocketChannel) selectionKey.channel();if (client.isConnectionPending()) {client.finishConnect();sendB.clear();sendB.put("Hello, Server".getBytes());sendB.flip();client.write(sendB);}client.register(selector, SelectionKey.OP_READ);} else if (selectionKey.isReadable()) {// 读事件client = (SocketChannel) selectionKey.channel();receB.clear();count = client.read(receB);if (count > 0) {String receMsg = new String(receB.array(), 0, count);System.out.println("receive from server " + receMsg);client.register(selector, SelectionKey.OP_WRITE);}} else if (selectionKey.isWritable()) {// 给客户端注册写事件client = (SocketChannel) selectionKey.channel();sendB.clear();String sendMsg = "index " + index;sendB.put(sendMsg.getBytes());sendB.flip();client.write(sendB);System.out.println("send to server " + sendMsg);client.register(selector, SelectionKey.OP_READ);}}// 模拟10个请求,并发10秒后同时执行connectionpublic static void main(String[] args) throws Exception {for(int i = 0; i<10;i++) {final int finalI = i;new Thread(new Runnable() {@Overridepublic void run() {System.out.println("========"+ finalI);try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}try {new NIOClient("127.0.0.1", 9779).connect();} catch (IOException e) {e.printStackTrace();}}}).start();}System.in.read();}}

6 MTU

TCP 协议向网络发包的时候,会把要发的数据先在缓冲区中进行囤积,当囤积到一定尺寸时(MTU),才向网络发送,这样可以最大化利用我们的网络带宽。而传输速度和性能也会变得很快。

【TCP】Recv-Q和Send-Q 不要在有什么误解了相关推荐

  1. TCP发送接口(如send(),write()等)的返回值与成功发送到接收端的数据量无直接关系

    1. TCP发送接口:send() TCP发送数据的接口有send,write,sendmsg.在系统内核中这些函数有一个统一的入口,即sock_sendmsg().由于TCP是可靠传输,所以对TCP ...

  2. http://q.cnblogs.com/q/54251/

    http://q.cnblogs.com/q/54251/ 转载于:https://www.cnblogs.com/ChengPuYuan/p/3293085.html

  3. Q学习(Q learning) 强化学习

    Q学习(Q learning) 强化学习的简单例子 Matlab实现 可视化_Morty 的挖坑记录-CSDN博客 强化学习(MATLAB) - 叮叮当当sunny - 博客园

  4. linux tcp socket 接收的字节数与发送的字节数不符,TCP发送接口(如send(),write()等)的返回值与成功发送到接收端的数据量无直接关系...

    1. TCP发送接口:send() TCP发送数据的接口有send,write,sendmsg.在系统内核中这些函数有一个统一的入口,即sock_sendmsg().由于TCP是可靠传输,所以对TCP ...

  5. 用ajax提交数据到ashx用JSON.stringify格式化参数后在服务器端取不到值?[转载至:http://q.cnblogs.com/q/34266/]...

    用ajax提交数据到ashx用JSON.stringify格式化参数后在服务器端取不到值?[转载至:http://q.cnblogs.com/q/34266/] 前台代码: $(function () ...

  6. c语言指针p=*q,C语言中指针*p=*q与p=q有什么区别

    满意答案 jiang1972 2018.02.01 采纳率:43%    等级:10 已帮助:21人 若p和q是申明为类型兼容的指针变量,且都正确赋有合法值且不为NULL,那么,*p=*q是把指针q指 ...

  7. 从”腾讯为什么要区分q币和q点”谈58与赶集余额商业产品

    从"腾讯为什么要区分q币和q点"谈58与赶集余额商业产品 缘起于个人思考:为什么腾讯有了Q币,还有搞Q点? 余额类产品是商业产品中很重要的一块,或许不复杂,但很有讲究,作为商业产品 ...

  8. 强化学习第一步:Q_learning 算法,Q现实与Q估计分不清楚?我来说说我的理解

    Q_learning 算法,Q现实与Q估计分不清楚 Q_learning 算法的一些简介 公式 Q现实与Q估计 Q_learning 算法的一些简介 是一种与模型无关的强化学习算法,直接优化一个可迭代 ...

  9. 【强化学习】Deep Q Network深度Q网络(DQN)

    1 DQN简介 1.1 强化学习与神经网络 该强化学习方法是这么一种融合了神经网络和Q-Learning的方法,名字叫做Deep Q Network. Q-Learning使用表格来存储每一个状态st ...

  10. [激光原理与应用-24]:《激光原理与技术》-10- 激光产生技术-调Q技术、Q开关、Q驱动器

    目录 第1章 调Q技术概述 1.1 什么是Q 1.2 什么是调Q技术 1.3 调Q的目的 1.4 调Q的原理 第2章 主要的调Q技术分类 2.2 电光调Q 2.3 被动调Q 第3章 调Q激光器参数对比 ...

最新文章

  1. 35岁中年博士失业,决定给后辈一些建议!
  2. 张小明教授+计算机,香港浸会大学、实验室兼职导师张晓明教授访问实验室并做学术报告...
  3. 功能对等四个原则_佛山房屋加固工程需遵循的原则与步骤
  4. 引用内部函数绑定机制,R转义字符,C++引用,别名,模板元,宏,断言,C++多线程,C++智能指针
  5. 命令行实现更强大的php交互
  6. linux++命令+q,linux 命令 - osc_panqs2jh的个人空间 - OSCHINA - 中文开源技术交流社区...
  7. 你必须足够强大,这个世界才会更加公平
  8. JavaScript 为何会成为最受欢迎的编程语言?
  9. 存储IO加强型实例I1+D1 ——为极致存储性能要求场景而生
  10. java jxl包_Java开源20个项目,最好别错过,帮助你灵活应对面试师的刁难
  11. 在eclipse中运行 carrot2 workbench
  12. 对 “悟空拼音”学习软件的教学过程优化分析
  13. Python CT图像预处理——nii格式读取、重采样、窗宽窗位设置
  14. 如果考研再来一次,你不会做哪些事情
  15. 网站服务器带宽2m怎么样,云服务器2m带宽够用吗
  16. python正则匹配括号内任意字符,python 正则匹配 获取括号内字符
  17. 中国天气雷达行业市场供需与战略研究报告
  18. python日期函数
  19. PHP+SQLServer2005+Apache/系统DSN配置+ODBC查插删改
  20. Node.js 微服务实践:基于容器的一站式命令行工具链...

热门文章

  1. linux脚本量产,可玩性很高的量产键盘、套件 HEAVY SHELL KIRA 96简单上手
  2. .wine/drive_c/users/Public/Application Data/Source Insight/4.0
  3. ​Windows域关系学习 全攻略
  4. GLUT, freeGLUT, GLFW, GLEW, GLAD 关系与区别
  5. WebSocket原生JavaScript实现简易聊天室
  6. RNN、RNNCell
  7. srand rand RAND_MAX
  8. (百万字废话乱写+1小时2000字码字速度养成计划)网络支付与结算读书笔记1(20120720)...
  9. tolua全教程-Chinar
  10. Java比较两个数组是否相等(equals())