TCP相关细节

1. 常用TCP参数

1.1 ReceiveBufferSize
ReceiveBuffersize指定了操作系统读缓冲区的大小, 默认值是8192(如图5-10 所示)。在第4章的例子中,会有"假设操作系统缓冲区的长度是8" 这样的描述,可通过socket.ReceiveBufferSize= 8 实现。当接收端缓冲区满了的时候,发送端会暂停发送数据,较大的缓冲区可以减少发送端暂停的概率, 提高发送效率

1.2 SendBufferSize
SendBuffersize 指定了操作系统写缓冲区的大小,默认值也是8192。对于那些没有处 理 好 “ 完整发送数据 ” 的网络模块 ( 见 4 . 5 节 ), 可以将SendBuffersize设成较大的值 , 以避免因发 送不完整而带来的各种问题 ( 图 5 - 1 0 )。 笔者见过有些还算成功的游戏项目 , 虽没有处理好数据的接收问题,但将 Sen dBuffer si ze 调大10倍,也能让游戏正常运转。

1.3 NoDelay
指定发送数据时是否使用Nagle 算法,对于实时性要求高的游戏,该值需要设置成 true Nagle 是一种节省网络流量的机制,默认情况下,TCP 会使用Nagle 算法去发送数据。
Nagle 算法的机制在于,如果发送端欲多次发送包含少量字节的数据包时,发送端不 会立马发送数据,而是积攒到了一定数量后再将其组成一个较大的数据包发送出去。
启用Nagle 算法可以提升网络传输效率,但它要收集到一定长度的数据后才会把它们 一 块儿发送出 去。这样一来,就 会降低网 络的实时性, 大部分实时网络游戏都会关闭 Nagle 算法,将socket.NoDelay 设置成true

1.4 TTL

TTL 指发送的IP数据包的生存时间值 (Time To Live , TTL ) 。 TTL 是 IP 头部的一 个值 ,
该值表示一个IP 数据报能够经过的最大的路由器跳数。发送数据时, TTL 默 认为64 (TTL 的默认值和操作系统有关,Windows
Xp默认值为128,Windows7默认值为64, Window10 默认值为6 5, Lin ux 默认值为 255 )。

数据在网络上传输, 实际上是经过多个路由器转发的。如图5- 13所示,发送端往接收端 发送一个卫数据报,初始的TTL
为64,在经过第一个理由器时,『头部的TTL减小,变成 63;
在经过第二个路由器时,变成了62。以此类推,直到TTL等于0,路由器就会丟弃数据。

在这里插入图片描述
在网络游戏中, 如果某些偏远地区用户时不时无法按收数据 , 可以尝试增大TTL值 ( socket.ttl=xxx)来解决问题。

1.5 ReuseAddress

Reuse Address 即端又复用 , 让同一个端又可被多个 socket 使用 。 一 般 情 况 下, 一 个 端 又只能由一个进程独占,假设服务端程序都绑定了1234端又,若开启两个服务端程序,虽 然, 第一个开启的程序能够成功绑定端又并监听,但第二个程序会提示“
端又己经在使用 中 ” , 无 法 绑 定 端 又。 在 计 算 机 中 , 退 出 程 序 与 释 放 端 又 并 不 同 步 。 在 5. 2 . 3 节 “ T C P 连 接 的终止〞 中,我们知道TCP断开连接会经历4次挥手。4次挥手需要时间,在网络不好的情况下,程序还会多次重试。当服务端程序崩溃,但它持有的Socket 不会被立马释放,这 时候重启 服务器就会遇到“ 端 又已经在使用中”的情形。等到Socket 被释放后(这个过程 可 能 要 十 几 分钟 时 间 ) , 服 务 端 才 能 成 功 重 启 。

对于人 气爆棚的大型网游, 十几分钟的等待时间会造成很大损失,一般要求在程序崩 溃 ( 尽 管 也 不 应 该 崩 溃, 但 人 算 不
如 天 算 ) 后 立 刻 重 启 , 继 续 提 供 服 务 。 端 又 复 用 最 常 见 的 用途是, 防止服务器 重启时,
之前鄉定的端又还未释放或者程序突然退出而系统没有释放 端 又。这种情况下如果设定了端又复用,则新启动的服务器进程可以直接鄉定端又。如果
没有设 定端又复用, 绑定会失败,提示端又己经在使用中,只好等十几分钟再重试了。 设 置 端又 复 用 使 用 s o c k e t 的
Sctsocket Option 方 法 , 代 码 如 下 所 示 。

Socket socket= new socket(AddressFamily.InterNetwork, socketrype.stream, ProtocolType.Tcp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

尽 管端又复用能解决服务端立即重启的问题,但它存在安全隐患。 主动关闭方有可能 在下次 使用时 收到上一次连接的数据包, 包括关闭连接响应包或者正常通信的数据包, 有可能出现奇怪现象

1.6 LingerState
LingerState 的功能是设置套接字保持连接的时间。

在这里插入图片描述
服务端中,会使用 下面的代码处理客户
端主动关闭连接,即在收到长度为0 的消息
后 , 调 用 clientfd.Close()关 闭 连 接 。
在这里插入图片描述
在这里插入图片描述
发送缓冲区还有尚末发送的数据, 那么直接调用Close 关闭连接,缓冲区中的数据将被丢弃。这种关闭方式很暴力,因为对端 可 能 还 需 要 这 些 数 据。 在 服 务 端 收 到 关 闭 信 号 后 , 有没有办法先把发送缓冲区中的数据发完,再关闭连接呢 ? LingerState 就是为了解决这个问题而诞生的 。

socket.LingerState = new LingerOption(true, 10);

其中的LingerOption 带有两个参数。第一个参数是LingerState.Enabled,代表是否启用 LingerState,只有设置为true 才能生效。第二个参数是LingerState.Linger Time,指定超时 时间。如果超时时间大于0 (比如10 秒),操作系统会尝试发送缓冲区中的数据,但如果网络状况不好,超过10秒还没有发完,它还是会强制关闭连接。
如果LingerState.LingerTime设置为0,系统会一直等到数据发完才关闭连接,无论等待多长时间。开启LingerOption能够在一定程度上保证发送数据的完整性。
在这里插入图片描述
服务端进入TIME_WAIT状态后,会等待一段时间再释放自由.对于高并发的服务端,过多的TIME_WAIT会占用系统资源,不是已经好事。有时候需要减小服务器的TIME_WAIT值,以求快速释放自由

2. Close的恰当时机

Lingerstate选项可以让程序在关闭连接前发完系统缓冲区中的数据,然而,这并不代表能将所有数据发出去。

下面完善代码使连接关闭时,依然能够完整发送数据。
对于主动关闭的一方(假设调用下述Close 方法关闭连接),应判断当前是否还有正在
发送的数据 。如有 , 只将标志位 isClosing 设置为 true , 等数据发送完再关闭连 接 ; 如果没有正在发送数据,直接调用socket.Close()关闭连接。代码如下:

bool isClosing = false;//关闭连接
public void Close() {//还有数据在发送if(writeQueue.Count > 0) {isClosing = true;} else { //没有数据在发送socket.Close();}
}

由于设置了isClosing 标志位,在关闭连接的过程中,程序只负责将已有的数据发送 完,不会发送新的数据。可以在Send 方法中添加判断,假如程序处于Closing状态,不能发送信息。代码如下:

//点击发送按钮 
public void Send ( )
{if (isClosing) {return;}// 拼接字节 , 省略组装 sendBytes 的代码byte[] sendBytes = 要发送的数据 ;ByteArray ba = new ByteArray (sendBytes);writeQueue.Enqueue (ba); // sendif(writeQueue.Count == 1){socket. BeginSend(ba.bytes, ba.readIdx, ba.length, 0, SendCallback, socket);}
}        

在BeginSend 回调两数中 , 还需要判断程序是否处于isClosing状 态, 如果程序发 送完写入队列的所有数据,而且处于isClosing 状态,应调用socket.Close 关闭连接。代码如下:

public void Sendcallback(IAsyncResult ar) {// 获取state、Endsend 的处理Socket socket = (Socket) ar.AsyncState; int count = socket.EndSend(ar);// 判断是否发送完整ByteArray ba= writeQueue.First (); ba.readIdx+=count;if(count ==ba.length){ //发送完整writeQueue. Dequeue ( );ba = writeQueue.First ();}   if(ba != null){//发送不完整,或发送完整且存在第二条数据 socket. BeginSend(ba.bytes, ba.readIdx, ba.length,
0, SendCallback, socket);} else if(isClosing) {socket.Close ( );}
}

3. 心跳机制

断开连接时, 主动方会给对端发送 F I N 信 号 , 开启4 次挥手流程 。 但在某些情况下, 比如拿着手机进人没有信号的山区,更极端的,比如有人拿剪刀把网 线剪断。虽然断开了连 接 , 但主动方无法给对端发送 FIN 信号 ( 网线剪断了还能干什么? ), 对端会认为连接有效,一直占用系统资源。

游戏开发中,TCP默认的KeepAlive 机制很“ 鸡肋”,因为上述的“一段时间” 太长, 默认为2小时 。 一般会自行实现心跳机制 。心跳机制是指客户端定时 ( 比 如 每 隔 1 分 钟 ) 向 服务端发送P I N G 消 息 , 服 务 端 收 到 后 回 应 P O N G 消 息 。 服 务 端 会 记 录客 户 端 最 后 一 次 发 送 P I N G 消 息 的 时 间 , 如 果 很 久 没 有 收 到 (比 如 3 分 钟 ) , 就 假 定 连 接 不 通, 服 务 端 会 关 闭 连 接 , 释放系统资源

心跳机制也有缺点,比如在短暂的故障期间,它们可能引起一个良好连接被释放; PING和PONG消息占用了不必要的宽带; 在流量如黄金的移动网络中,会让玩家花贵更多 的流量费。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/27748.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实用软件下载:XMind 2024最新安装包及详细安装教程

​XMind不仅是一款易用且功能强大的思维导图软件,也是一个开源项目。XMind以构建一个社区向全球提供领先的跨平台思维导图和头脑风暴软件为目标,以帮助用户提升效率。XMind公司是XMind开源项目的主要代码贡献者,与此同时,我们欢迎…

Stable Diffusion本地化部署详细攻略

一、硬件要求 内存:至少16GB 硬盘:至少60GB以上的磁盘空间,推荐SSD固态硬盘 显卡:推荐NVIDIA显卡 显存:至少4GB Stabl Diffusion因为是在本地部署,对显卡的要求比较高,如果经济能力可以的话…

AI大模型爆发,你还不学就晚了!抓住时代机遇,快速入门指南!

AI大模型风起云涌,你准备好乘风破浪了吗? 在一个阳光明媚的午后,小李坐在自己的工位上,眼前的代码如同繁星般繁多。他是一名资深的软件工程师,但在最近的技术浪潮中,他却感到了一丝不安。他的朋友圈里&…

RN6752V1 高性能AHD转MIPIDVPBT656BT601芯片方案,目前适用于车载方案居多

RN6752V1描述: RN6752V1是一种模拟高清晰度(模拟高清)视频解码器IC,专为汽车应用而设计。它集成了所有必要的功能块: AFE,PLL,解码逻辑,MIPI和I2C接口等,在一个小的5mm …

LLM资料大全:文本多模态大模型、垂直领域微调模型、STF数据集、训练微调部署框架、提示词工程等

前言 自ChatGPT为代表的大语言模型(Large Language Model, LLM)出现以后,由于其惊人的类通用人工智能(AGI)的能力,掀起了新一轮[自然语言处理]领域的研究和应用的浪潮。尤其是以ChatGLM、LLaMA等平民玩家都…

【ARM Cache 及 MMU 系列文章 6.5 -- 如何进行 Cache miss 统计?】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 文章目录 ARM Cache Miss 统计Cache 多层架构简介Cache 未命中的类型Cache 未命中统计Cache miss 统计代码实现Cache Miss 统计意义ARM Cache Miss 统计 在ARMv8/v9架构中,缓存未命中(Cache …

人工智能在风险管理中的创新之路

随着科技的飞速发展,人工智能(AI)已经渗透到我们生活的方方面面,尤其在风险管理领域,其展现出的巨大潜力令人瞩目。风险管理,作为一个涉及广泛领域的复杂系统,正逐渐依赖于AI技术来提升效率和准…

简单了解CPU的工作原理

目录 一、基本结构以及对应功能 (1)基本结构 (2)几个重要寄存器的详细介绍 操作码 (Opcode) 操作数 (Operands) 指令表 (Instruction Table) 第一个:程序计数器 (PC) 第二个:指令寄存器 (IR&#x…

【Arthas案例】某应用依赖两个GAV不同但包含两个相同全限定类名StaticLoggerBinder,引起log4j.Level类找不到异常

3分钟内解决问题 两个不同的GAV依赖冲突,包含相同全限定类名,引起ClassNotFoundException Maven依赖的三坐标体系GAV(G-groupId,A-artifactId,V-version) 【案例1】某应用依赖两个GAV不同的jar,但包含两个相同全限定类…

探索互联网寻址机制 | 揭秘互联网技术的核心,解析网络寻址

揭秘互联网技术的核心,解析网络寻址题 前提介绍局域网地址IP地址的分配方式动态IP分配机制内部网(intranet)ICANN负责IP分配DHCP协议获取IP地址 域名系统域名是什么域名工作方式hosts文件存储域名映射关系DNS分布式数据库DNS域名解析 Java进行…

Java中List流式转换为Map的终极指南

哈喽,大家好,我是木头左! 在Java编程中,经常需要将一个List对象转换为另一个Map对象。这可能是因为需要根据List中的元素的某些属性来创建一个新的键值对集合。在本文中,我将向您展示如何使用Java 中的流式API轻松地实…

02_01_SpringMVC初识

一、回顾MVC三层架构 1、什么是MVC三层 MVC是 模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。主要作用是降低视图与业务逻辑之间的双向耦合,它不是一种…

Linux文本处理三剑客+正则表达式

Linux文本处理常用的3个命令,脚本或者文本处理任务中会用到。这里做个整理。 三者的功能都是处理文本,但侧重点各不相同,grep更适合单纯的查找或匹配文本,sed更适合编辑匹配到的文本,awk更适合格式化文本,对…

Elasticsearch 为时间序列数据带来存储优势

作者:来自 Elastic Martijn Van Groningen, Kostas Krikellas 背景 Elasticsearch 最近投资了对存储和查询时间序列数据的更好支持。存储效率一直是关注的主要领域,许多项目取得了巨大的成功,与将数据保存在标准索引中相比,可以节…

基于java的英文翻译字典

基于java的英文翻译字典,附有源代码,源数据库初始化文件 源码地址 dict_demo: 提取一段英文对话中的英文词汇,输出为英文单词字典形式 解析json字条 private void readFile(String pathname) {long start System.currentTimeMillis(); //…

微服务链路追踪ELK

微服务链路追踪&ELK 链路追踪概述链路追踪sluthzipkinelk日志管理平台 一 链路追踪 1 概述 1.1 为什么需要链路追踪 ​ 微服务架构是一个分布式架构,它按业务划分服务单元,一个分布式系统往往有很多个服务单元。由于服务单元数量众多&#xff0…

PostgreSQL 快速入门与实战

1、概述 前面2篇博客给大家详细的介绍了PostgreSQL的安装和配置,本篇文章就带着大家一起学习一下PostgreSQL的用法,主要内容包括 基本的数据库操作、用户管理、数据备份、SCHEMA(模式)以及和MySQL的区别。 2、数据库基本操作 PostgreSQL是严格遵守SQL规…

基于System-Verilog的FPGA设计与仿真

一、System-Verilog System Verilog的发展 SystemVerilog 的出现是为了因应日益复杂的数位电路设计和验证需求。虽然Verilog HDL 在早期的数位电路设计中得到了广泛应用,但随着技术的发展和电路复杂度的增加,Verilog HDL 在某些方面已经显得有些不足以满…

leetcode 56合并区间

思路 合并就是首先应该按照left左边界排序,排完序以后,如果i的左边界小于等于i-1的右边界,说明有重合,此时这两个可以合并,右边界应该取最大值。 代码 排序 我是定义了一个类,存储左右边界,先将数组转化…

Linux Centos 环境下搭建RocketMq集群(双主双从)

1、下载rocketmq的包 下载 | RocketMQ 2、配置环境变量 1、编辑环境变量文件:vim /etc/profile2、加入如下配置: #rocketmq 4.9.8 ROCKETMQ_HOME/home/rocketmq/rocketmq-4.9.8 export PATH${ROCKETMQ_HOME}/bin:${PATH}3、刷新配置:source…