《Unity3D网络游戏实战》深入了解TCP

news2024/9/20 6:47:33

从TCP到铜线

应用层

应用层功能是应用程序(游戏程序)提供的功能。在给客户端发送“hello”的例子中,程序把“hello”转化成二进制流传递给传输层(传送给send方)​。操作系统会对二进制数据做一系列加工,使它适合于网络传输。

传输层

收到二进制数据后,传输层协议会对它做一系列加工,并提供数据流传送、可靠性校验、流量控制等功能。

网络层

IP协议会给TCP数据添加本地地址、目的地地址等信息

数据传输流程

TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,与TCP相对应的UDP协议是无连接的、不可靠的协议,但传输效率比TCP高。

TCP连接的建立

在TCP/IP协议中,TCP协议提供可靠的连接服务,连接是通过三次握手进行初始化的。三次握手的目的是同步连接双方的序列号和确认号并交换TCP窗口的大小信息

连接方调用Connect后,Client(连接方)向Server(监听方)发送一个数据包SYN, SYN包含了序列号seq,这是以后传送数据时要使用的。Server收到数据包后由标志位SYN知道Client请求建立连接,Server将SYN/ACK数据包发送给Client以确认连接请求。Clients收到SYN/ACK数据包后Connect返回,连接成功

TCP的数据传输

发送一个数据后,发送方并不能确保数据被对方接收。于是发送方会等待接收方的回应,如果太长时间没有收到回应,发送方会重新发送数据。发送数据时,TCP会考虑对方缓冲区的容量,当对方缓冲区满时,会暂停发送数据,防止对端溢出。TCP还会根据数据返回的时间判断网络是否拥堵,如果网络拥堵就减慢发送的速度,以求“道路畅通”​。

TCP连接终止

TCP通过“四次挥手”确保双端释放socket资源

  • 第一次挥手:主机1(可以是客户端也可以是服务端)向主机2发送一个终止信号(FIN)​,此时,主机1进入FIN_WAIT_1状态,它没有需要发送的数据,等待着主机2的回应。
  • 第二次挥手:主机2收到了主机1发送的终止信号(FIN)​,向主机1回应一个ACK。收到ACK的主机1进入FIN_WAIT_2状态。
  • 第三次挥手:在主机2把所有数据发送完毕后,主机2向主机1发送终止信号(FIN)​,请求关闭连接。
  • 第四次挥手:主机1收到主机2发送的终止信号(FIN)​,向主机2回应ACK。然后主机1进入TIME_WAIT状态(等待一段时间,以便处理主机2的重发数据)​。主机2收到主机1的回应后,关闭连接。至此,TCP的四次挥手便完成了,主机1和主机2都关闭了连接

常用TCP参数

ReceiveBufferSize

ReceiveBufferSize指定了操作系统读缓冲区的大小,默认值是8192,可以通过 socket. ReceiveBufferSize = 8 这样来指定缓冲区的长度

SendBufferSize

SendBufferSize指定了操作系统写缓冲区的大小,默认值也是8192

NoDelay

指定发送数据时是否使用Nagle算法,对于实时性要求高的游戏,该值需要设置成false。Nagle是一种节省网络流量的机制,默认情况下,TCP会使用Nagle算法去发送数据。

TTL

TTL指发送的IP数据包的生存时间值(Time To Live, TTL)​。TTL是IP头部的一个值,该值表示一个IP数据报能够经过的最大的路由器跳数。发送数据时,TTL默认为64

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

ReuseAddress

ReuseAddress即端口复用,让同一个端口可被多个socket使用。一般情况下,一个端口只能由一个进程独占,假设服务端程序都绑定了1234端口,若开启两个服务端程序,虽然,第一个开启的程序能够成功绑定端口并监听,但第二个程序会提示“端口已经在使用中”​,无法绑定端口。

当服务端程序崩溃,但它持有的Socket不会被立马释放,这时候重启服务器就会遇到“端口已经在使用中”的情形。等到Socket被释放后(这个过程可能要十几分钟时间)​,服务端才能成功重启。

设置端口复用使用socket的SetSocketOption方法,代码如下所示。

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

LingerState

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

客户端调用Close()关闭Socket连接(客户端或服务端关闭连接都是同样的流程,服务端主动关闭连接同理)​,这时,客户端会给服务端发送FIN信号(①)​,然后进入等待。当服务端收到FIN信号时,会返回一个长度为0的数据,然后向客户端回应信息(②)​。这也是为什么关闭连接时,对端Receive会收到0个数据。如果服务端不做处理,客户端将会持续等待。

服务端中,会使用下面的代码处理客户端主动关闭连接,即在收到长度为0的消息后,调用clientfd.Close()关闭连接。

    public static void ReceiveCallback(IAsyncResult ar){
        ……
        int count = clientfd.EndReceive(ar);
        //客户端关闭
        if(count == 0){
            clientfd.Close();
            ……
            return;
        }
        ……
    }

服务端在调用Close后,它向客户端发送FIN信号(③)​,然后等待客户端回应。当服务端收到客户端的回应信息时,它会释放socket资源,真正完成关闭连接的流程。对客户端来说,它在收到服务端的FIN(③)信号后,会进入一个称为TIME_WAIT的状态,等待一段时间后(Windows下默认为4分钟)​,才会释放socket资源,真正完成关闭连接的流程。TIME_WAIT状态的意义在于,如果网络状况不好,服务端迟迟没有收到客户端回应的信号(④)​,那它会重发FIN信号(③)​,客户端socket需要维持一段时间,以回应重发的信号,确保对方有很大概率能够收到回应信号(④)​。

这种机制可以让服务端在关闭连接前处理尚未完成的事情,例如,假设收到客户端FIN信号时,服务端socket处于图片显示的状态,即发送缓冲区还有尚未发送的数据,那么直接调用Close关闭连接,缓冲区中的数据将被丢弃。这种关闭方式很暴力,因为对端可能还需要这些数据

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

其中的LingerOption带有两个参数。第一个参数是LingerState.Enabled,代表是否启用LingerState,只有设置为true才能生效。第二个参数是LingerState.LingerTime,指定超时时间。如果超时时间大于0(比如10秒)​,操作系统会尝试发送缓冲区中的数据,但如果网络状况不好,超过10秒还没有发完,它还是会强制关闭连接。如果LingerState.LingerTime设置为0,系统会一直等到数据发完才关闭连接,无论等待多长时间。开启LingerOption能够在一定程度上保证发送数据的完整性

心跳机制

TCP有一个连接检测机制,就是如果在指定的时间内没有数据传送,会给对端发送一个信号(通过SetSocketOption的KeepAlive选项开启)​。对端如果收到这个信号,回送一个TCP的信号,确认已经收到,这样就知道此连接通畅。如果一段时间没有收到对方的响应,会进行重试,重试几次后,会认为网络不通,关闭socket。

    Socket.SetSocketOption(SocketOptionLevel.Socket,  SocketOptionName.KeepAlive,
true)

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

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

相关文章

嵌入式八股文-网络编程、多线程和进程

网络编程 1. TCP头部结构 TCP固定头部结构 每个TCP报文段都包含着此报文段的TCP头部信息,用于指定源端端口、目的端端口以及管理TCP连接等。完整的TCP头部结构可分为固定头部结构和头部选项两个部分。 32位端口号:包括了16位源端口号和16位目的端口号。32位序号:假设第一次…

Linux驱动开发基础(Hello驱动)

所学内容来自百问网 目录 1. 文件在内核中的表示 2. 打开字符设备节点时,内核中也有对应的struct file 3. 编写驱动程序步骤 4. 相关知识点 4.1 涉及函数解析 4.2 module_init/module_exit的实现 4.3 register_chrdev的内部实现 4.4 class_destroy/device_…

(Jmeter、Fiddler)脚本转换Loadrunner脚本

背景:公司政治任务、各种体系文档要留档,但有些不在体系内的工具生成的脚本需要转化到体系内以备留档。 一、Loadrunner代理设置 开始录制配置: Record->Remote Application via LoadRunner Proxy LoadRrunner Proxy listens on port-> 8889 (系统建立出入站规则…

解析防蠕动交叉导轨的防蠕动机制

随着工业自动化的不断发展,对机械导轨系统的精度和稳定性要求越来越高。防蠕动交叉导轨作为一种新型导轨系统,能够有效提高设备的运行精度和稳定性,降低维护成本。 蠕动现象通常发生在导轨负载超出其额定范围、表面粗糙度不足或润滑不良等情况…

Python 实现 Excel 文件操作的技术性详解

目录 一、引言 二、Excel 文件格式及库的选择 2.1 Excel 文件格式 2.2 库的选择 三、安装必要的库 四、使用 openpyxl 读取 Excel 文件 4.1 基本步骤 4.2 实战案例 五、使用 pandas 读取 Excel 文件 5.1 基本步骤 5.2 实战案例 六、写入 Excel 文件 6.1 使用 …

【每日刷题】Day100

【每日刷题】Day100 🥕个人主页:开敲🍉 🔥所属专栏:每日刷题🍍 🌼文章目录🌼 1. 【模板】堆_牛客题霸_牛客网 (nowcoder.com) 2. 【模板】链表_牛客题霸_牛客网 (nowcoder.com) 3…

Linux系统移植——开发板烧写

目录: 目录: 一、什么是EMMC分区? 1.1 eMMC分区 1.2 分区的管理 二、相关命令介绍: 2.1 mmc 2.1.1 主要功能 2.1.2 示例用法 2.2 fdisk 2.2.1 基本功能 2.2.2 交互模式常用命令 2.2.3 注意事项 三、U-BOOT烧写 3.1 mmc命令 3.2 f…

24小时监控识别潜在的非安全生产隐患的明厨亮灶开源了。

明厨亮灶视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。AI技术可以24小时…

【JS】旋涡数组

前言 实现如下图的旋涡数组,简单理解为遇到拐点自动拐弯,否则一直沿当前方向推进。 封装一个函数接收两个参数分别为行数以及列数,实现该旋涡数组。 思路 二维数组,初始填充0分别记录水平和垂直方向的坐标,并根据步…

学习记录702@计算机组成原理之计算机硬件组成细化

运算器 ACC是累加器ALU是逻辑和算数运算单元MQ是乘商寄存器 X是操作数寄存器各部分存储的值 控制器 PC是程序计数器,用来存放下一条应该执行程序的地址,与MAR地址寄存器相连,找到下一个要执行的程序的地址。IR指令寄存器,用来…

怎么利用XML发送视频彩信

传统的短信推广主要以文字为主,用户接收到的信息往往显得单调乏味。而视频彩信则不同,它结合了视频和音频的优势,通过生动的画面和悦耳的音乐,给用户带来强烈的视听冲击,从而极大地提高了用户的吸引力。 XML成功返回示…

某通电子文档安全管理系统 CDGAuthoriseTempletService1接口SQL注入漏洞复现 [附POC]

文章目录 某通电子文档安全管理系统 CDGAuthoriseTempletService1接口SQL注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现0x06 修复建议某通电子文档安全管理系统 CDGAuthoriseTempletService1接口SQL注入漏…

聚鼎科技:现在开一家装饰画店铺究竟受欢迎吗

在这个时代,装饰画不仅仅是墙上的一抹色彩,它已经成为人们情感寄托、审美追求的象征。那么,现在开一家装饰画店铺究竟受欢迎吗? “家,是一幅画。”这句话道出了现代人对于家的期待与向往。在这个快节奏的时代,人们渴望…

8.13 哈希表中等 128 Longest Consecutive Sequence 138 Copy List with Random Pointer

128 Longest Consecutive Sequence class Solution { public:int longestConsecutive(vector<int>& nums) {//无序array整数数组&#xff0c;返回最长的连续的序列长度&#xff0c;首先这些数不按顺序//时间复杂度O(n)//使用哈希表&#xff0c;先存后遍历---->no …

web页面的性能测试

背景 测试大模型主要web页面的性能 使用工具 通过google自带的lighthouse测试页面的性能 各个参考指标 First Contentful Paint(FCP):测量在用户导航到页面后浏览器呈现第一段 DOM 内容所花费的时间。页面上的图像、非白色<canvas>元素和 SVG 被视为 DOM 内容&#…

C++STL之string类:基本使用及模拟实现

目录 一&#xff0c;前言 为什么要学习string类 C语言中的字符串 C中的字符串 STL(Standard Template Library) 里面的 string 类 二&#xff0c;string类的基本使用 文档的阅读 常见接口的基本使用 1&#xff0c;构造函数(constructor) 2&#xff0c;拷贝构造(copy …

程序员喜欢的7个免费公共API

本文将介绍七个程序员们喜爱的免费公共API&#xff0c;它们覆盖了从天气信息、翻译到数据分析、游戏等多个领域。这些API不仅易于使用&#xff0c;而且功能全面&#xff0c;能够帮助开发者快速实现项目需求&#xff0c;无论是个人学习、小项目开发还是商业应用&#xff0c;都能…

诸葛io孔淼:聚焦区域性银行,新一代自主可控的埋点分析平台

近日&#xff0c;由金科创新社主办的2024金融科技创新发展论坛顺利召开&#xff0c;诸葛智能创始人孔淼受邀出席并发表演讲&#xff0c;他表示&#xff0c;区域性银行需要构建新一代的数智化营销体系&#xff0c;驱动营销效率与经营效能增长。 孔淼指出&#xff0c;中小银行应…

Flink UDF注意幂等性,防止重复调用时出问题

编写Flink UDF 要注意幂等性&#xff0c;尤其不能直接修改入参&#xff01;理论上是一条数据只会执行一次UDF&#xff0c;但是实际执行过程中可能会对一条数据执行多次UDF&#xff0c;引起意想不到的问题。 例如有如下SQL&#xff1a; CREATE VIEW tmp_view AS SELECT a.…

Processing圆圈随鼠标运动

一.案例代码如下&#xff1a; import processing.pdf.*; import java.util.Calendar; boolean savePDF false; float tileCount 20; color circleColor color(0); int circleAlpha 180; int actRandomSeed 0; void setup(){ size(600,600); } void draw(){ if(savePD…