type
status
date
slug
summary
tags
category
icon
password
fullWidth
fullWidth
System.Net命名空间
- System.Net 是 .NET 框架中的一个命名空间,提供了用于网络编程的类和方法。它简化了许多常见网络协议的编程接口,使开发者能够轻松地创建网络应用程序
IPAddress
- 表示IP地址,有3种初始化方式
- 使用byte数组初始化IPAddress,IP地址由4个byte组成
- 使用16进制长整型初始化
IPAddress
- 使用
IPAddress
中的静态方法Parse
做字符串转换
IPEndPoint
- 表示IP地址和端口号的组合,有2种初始化方式:
- 用长整型表示IP地址,整型表示端口号
- 用
IPAddress
对象表示IP地址,整型表示端口号
IPHostEntry
- 返回域名解析的结果,包含IP地址、主机名等信息;该类一般不声明,而是作为某些方法的返回值
IPHostEntry
类
Dns
- .NET中的静态类,提供一组方法用于与域名系统 (DNS) 服务器进行交互
- 获取本地主机的名称
- 同步获取指定域名的IP信息,会阻塞主线程,有2个重载
- 异步获取指定域名的IP信息,在主线程中开启异步方法,有2个重载
网络传输中的数据
- 序列化:把想要传递的类对象信息序列化为二进制数据传输给远端设备
- 反序列化:远端设备获取到二进制数据后反序列化成类对象
BitConverter
类,命名空间:System;作用是除字符串的其他常用类型和字节数组的相互转换GetBytes
方法,有多个重载,可以传入整型、浮点型、字符、布尔类型
Encoding
类,命名空间:System.Text;作用是将字符串类型和字节数组相互转换,一般使用UTF-8编码类型GetBytes
方法,有多个重载,可以传入string
或char[]
序列化
- 类对象序列化成字节数组的过程
- 在类中封装
GetBytes
方法,得到该类对象转换成的二进制数据 - 明确字节数组的容量
- 声明一个装载字节数组的容器
- 将对象中的所有属性转换为字节数组并放入容器
反序列化
- 将字节数组转换为原始的数据结构
- 转换成非字符串类型:使用
BitConverter
中的ToInt32
、ToDouble
、ToFloat
、ToChar
、ToBoolean
等方法 - 转换成字符串类型:使用
Encoding
中的GetString
方法,有多个重载
- 将字节数组转换为转换成类对象
- 获取到字节数组playerBytes
- 将字节数组按照类的成员变量序列化时的顺序反序列化,得到各成员变量的值
- 重建类对象
可序列化和反序列化类的基类
- 可以用一个抽象类作为可序列化类的基类,需包含以下方法
- 获取字节数组容器的长度
- 把成员变量序列化存入字节数组并返回
- 读取字节数组反序列化到成员变量中
- 各常用数据类型和该类对象的序列化和反序列化的方法
- 具体实现案例
- 类对象可以作为另一个类的成员变量,如
TestInfo
类中的player
,序列化时直接调用该类对象的WriteObject
方法(前提是作为成员变量的类也需要集成自BaseData)
- 序列化和反序列化测试
- info1:需要序列化的类对象
- bytes:info1序列化后的字节数组
- info2:从bytes反序列化的类对象,用于重建info1
Socket
Socket
是C#提供的用于网络通信的类(在其他语言中也有Socket类),位于System.Net.Sockets命名空间
- Socket套接字是支持TCP/IP网络通信的基本操作单位,包含
- 本机的IP地址和端口
- 对方主机的IP地址和端口
- 使用的协议
- 一个Socket对象可被视为一个数据通道,连接客户端和服务端,用来收发消息
- C#中通过构造函数声明Socket的类型,构造函数有多个重载
Socket的分类
- 流套接字:用于实现TCP通信,提供面向连接的、可靠的、有序的、不丢失无重复的数据传输服务
- 数据报套接字:用于实现UDP通信,提供无连接的、不可靠的、不保证顺序的、可能出现丢失和重复的数据传输服务
- 原始套接字:用于实现IP数据报通信,直接访问协议的较低层,用于监听和分析数据报
TcpSocket常用方法
- 服务端专用方法
- 客户端专用方法
- 双端通用方法
- TCP协议的三次握手和四次挥手封装在Socket内部,无需额外处理
- TCP协议三次握手在Socket中的体现
- TCP协议四次挥手在Socket中的体现


- 简单的网络通信步骤
服务端TcpSocket
- 使用线程等待客户端连接,使用线程接收客户端消息,使用线程池处理客户端消息
- 问题和分析
- 在控制台输入"Quit"后,clientSocket = clientSockets[i]这一行报错:
- 原因分析:在控制台输入"Quit"后,主线程执行了
clientSockets.Clear()
;但线程池中的接收消息的方法仍在for循环遍历中,而clientSockets的列表元素个数已清零 - 解决方法:拷贝一份clientSockets副本;使用并发集合;标记并延迟删除...
封装
- ClientSocket模块:封装客户端Socket,管理单个客户端Socket的状态;提供发送、接收消息等功能
- ServerSocket模块:管理所有连入的客户端Socket;提供开启、监听连入、接收消息、发送消息等方法
客户端TcpSocket
- 客户端Socket封装在网络模块(NetManager)中,提供开启连接、断开连接、发送消息、接收消息的方法
- 发送消息、接收消息各开一个线程,不阻塞主线程;子线程与主线程的数据交互通过消息队列进行
区分消息类型
- 网络通信中,使用字节数组进行数据传递,接收到消息时需要知道数据类型,才能使用对应的类来反序列化。
- 解决方法:为发送的信息添加标识(ID),标识可以是
int
、short
、bytes
、long
等数据类型。 - 如果使用int类型作为消息ID,前4个字节是消息ID,后面的字节是消息内容。
- 创建消息基类,基类继承自
BaseData
并添加消息ID的属性和获取方法。
- 需要传递消息的类继承该基类,序列化时需要加上消息ID,反序列化时无需解析消息ID
分包和粘包
- 定义:分包、粘包指网络通信中由于各种因素造成的消息与消息之间出现的两种状态,可能同时发生
- 分包:一个消息分成多个消息进行发送
- 粘包:一个消息和另一个消息黏在一起
- 出现原因:
- 分包:当一个数据包过大,超过了网络传输的最大传输单元或TCP发送缓冲区的大小时,数据包会被拆分成多个小包进行传输。
- 粘包:当多个小数据包在发送时被合并成一个大包进行传输,或者接收端在一次读取操作中接收到多个数据包时,数据包会粘在一起。
解决方法
- 固定长度封装:将每个数据包封装成固定长度,不足部分用填充字符填充,这种方法简单但可能浪费带宽。
- 使用分隔符:在每个数据包的末尾使用固定的分隔符(如 \r\n),接收端通过分隔符来区分不同的数据包,这种方法适用于文本数据传输。
- 消息头包含长度信息:在数据包的头部包含消息长度信息,接收端根据长度信息读取完整的数据包,这是最常用的方法,适用于大多数应用场景;方法如下:
- 判断字节数组的状态的依据:消息长度
- 为消息添加头部,头部记录消息的长度
- 接收消息时通过消息长度来判断是否分包、粘包
- 从而对消息进行合并、拆分处理
- 一个消息由以下部分构成:
- 消息ID
- 消息长度
- 消息体
- 自定义协议:设计自定义协议来处理分包和粘包问题。例如,使用Netty框架中的解码器来处理。
消息长度方法的实践
- 消息类中的给消息的头部添加消息长度:
GetBytesLength
返回的字节数组长度新增消息体长度的长度ConverToByteArray
把消息体长度写入字节数组
- 接收单条消息的方法,在线程方法中调用
- 声明用于缓存消息的容器
- 单条消息的处理方法
- 处理流程

自定义退出消息
- 解决的问题:
- 服务端的
socket.Connect
变量表示的是上一次收发消息是否成功,因此无法准确判断客户端状态 - 因此需要自定义退出消息,由客户端断开时主动发送,服务端接收到后把对应socket从字典中移除
- 客户端的处理:
- 新增
QuitMessage
类表示自定义退出消息(服务端同步添加此类) - 在
NetManager.Close
方法中调用
- 服务端的处理:
ServerSocket
中新增待删除的Socket列表delList和添加列表的方法ServerSocket
中新增关闭客户端Socket并从clientDict中移除的方法ServerSocke.Receive
中遍历字典调用每个客户端Socket的接收方法之后,要移除待移除列表中的SocketClientSocket.HandleReceiveMessage
中新增自定义退出消息的ID判断ClientSocket.HandleMessage
中如果判断类型为QuitMessage,把自身加入待删除列表
心跳消息
- 定义:心跳信息是长连接中,客户端和服务端之间定期发送的一种特殊的数据包;用于通知对方自己还在线,以确保长连接的有效性
- 为什么需要心跳消息:
- 避免非正常关闭客户端时,服务器无法正常收到退出消息
- 自定义超时判断,如果超出某一时间没收到客户端的消息,证明客户端已断开连接
- 避免客户端长期不发送消息,防火墙或路由器会断开连接,用心跳消息保持活跃状态
- 客户端实现:
- 自定义心跳消息类
- NetManager中用
Invoke
定时发送心跳消息
- 服务端实现:
ClientSocket.HandleReceiveMessage
新增心跳消息类型的判断ClientSocket.HandleMessage
更新上次收到心跳消息的时间ClientSocket.CheckTimeOut
检测是否超时,若超时就把自身加入待删除列表
ClientSocket.Receive
新增检测是否超时的方法,而Receive本身就在ServerSocket的帧循环中调用
异步通信常用方法
同步方法和异步方法的区别:同步方法是阻塞模式+顺序执行,调用者必须等待方法执行完成后才能继续执行后续操作;异步方法是非阻塞模式+并发执行,调用者可以在方法执行过程中执行其他操作。
C#网络通信模块中有两种异步方案,内部开多线程,通过回调形式返回结果
Begin开头的API:通过
AsyncCallback
参数传入回调函数,需要与End开头的方法配合使用Async结尾的API:依赖
SocketAsyncEventArgs
对象,通过在Complete参数中添加回调函数Begin
- 服务端专用:
BeginAccept
和EndAccept
- 客户端专用:
BeginConnect
和EndConnect
- 服务端和客户端通用
- 接收消息:
BeginReceive
和EndReceive
- 发送消息:
BeginSend
和EndSend
Async
- 服务端专用:
AcceptAsync
- 在委托
Completed
中添加回调函数
- 客户端专用:
ConnectAsync
- 在委托
Completed
中添加回调函数
- 服务端和客户端通用
- 发送消息:
SendAsync
- 接收消息:
ReceiveAsync
最大传输单元
- 最大传输单元(Maximum Transmission Unit, MTU)是通知通信对方能接受的数据服务单元的最大尺寸;以太网和802.3协议对数据帧的长度限制最大值分别为1500字节和1492字节
- 为了避免自动分包,需要限制最大传输单元;由于UDP包本身带有头部信息28,建议:
- 局域网环境下,1472字节以内
- 互联网环境下,548字节以内
Udp通信的简单应用
- Udp通信中客户端和服务端的收发逻辑一致
客户端
- Udp客户端通信实现收发字符串
服务端
- Udp服务端通信实现收发字符串
Udp通信异步方法
Begin
- 发送消息:
BeginSendTo
和EndSendTo
- 接收消息:
BeginReceiveFrom
和EndReceiveFrom
Async
- 发送消息:
SendToAsync
- 接收消息:
ReceiveFromAsync
FTP
- FTP是文件传输协议,使用户可以把文件从一台主机拷贝到另一台主机上,除此之外,还提供登录、目录查询和绘画控制等功能。
- FTP的本质是TCP通信:通过FTP传输文件,双方至少需要建立两个TCP连接,一个是控制连接,用于传输FTP命令;一个是数据连接,用于传输文件数据。
- FTP有两种传输模式
- 主动模式(Port模式):服务器主动连接客户端并传输文件
- 被动模式(Passive模式):客户端主动连接服务器(控制连接和数据连接都由客户端发起)
- FTP有两种数据传输方式
- ASCII传输方式:以ASCII编码方式传输数据,适用于传输仅包含英文的命令和文件
- 二进制传输方式:可以指定编码方式传输命令和文件数据,应用较广
关键类
NetworkCredential
:通信凭证类
FtpWebRequest
:Ftp文件传输协议客户端操作类Create
:创建新的WebRequest
,用于Ftp相关操作
Abort
:终止正在传输的文件
GetRequestStream
:获取用于上传的流
GetResponse
:返回FTP服务器的响应
- 成员变量
FtpWebResponse
:FTP服务器对请求的响应Close
:释放所有资源
GetResponseStream
:返回从FTP服务器下载数据的流
- 成员变量
HTTP
- HTTP是超文本传输协议,是因特网上应用最广泛的一种网络传输协议;最初设计HTTP的目的是为了提供一种发布和接收由文本文件组成的HTML页面的方法,后来发展到除了文本数据外,还可以传输图片、音频、视频、压缩文件以及各种程序文件。
- HTP的本质是TCP通信,因此不会丢包、乱序;它定义了Web客户端(一般指浏览器)如何从Web服务器请求Web页面,以及服务器如何把Web页面传给客户端。
- HTTP的工作原理
- 以TCP方式工作
- 是无状态的
- 使用元信息作为标头
- HTTP/1.0仅支持短连接,HTTP/1.1支持持久连接,可以连续发送请求,并在上一个请求应答之前发送多个请求;目前使用的基本都是HTTP/1.1。
- HTTP协议的请求类型
- GET:请求获取特定的资源,比如请求一个Web页面或请求获取一个资源
- POST:请求提交数据进行处理,比如请求上传一个文件
- HEAD:请求获取特定的资源,但是不会返回具体内容,只返回消息头
- PUT:向指定位置上传最新内容
- DELETE:删除指定资源
- OPTIONS:返回服务器针对特定资源支持的HTTP请求方法
- TRACE:回显服务器收到的请求
- CONNECT:预留给能够将连接改为管道方式的代理服务器
- HTTP的请求格式
- <request line>:请求行,说明请求类型、HTTP版本
- <headers>:标头,服务端会使用的附加信息
- <blank line>:空行,表明标头结束
- <request body>:消息主体,可以包含任何数据
- HTTP的响应格式
- <status line>:状态行,提供一个状态码来说明请求情况
- <headers>:标头,客户端会使用的附加信息
- <blank line>:空行,表面标头结束
- <request body>:消息主体,可以包含任何数据
关键类
HttpWebRequest
:发送客户端请求的类Create
:创建新的WebRequest
,用于进行HTTP相关操作
Abort
:如果正在进行文件传输,用此方法可终止传输
GetRequestStream
:获取用于上传的流
GetResponse
:返回HTTP服务器响应
- 成员变量
HttpWebResponse
:获取服务器返回信息的类Close
:释放资源
GetResponseStream
:返回从FTP服务器下载数据的流
- 成员变量
Get和Post请求
- GET和POST是HTTP协议中最常用的两种请求方法,它们在数据传输方式、用途和安全性等方面有显著差异
- 数据传输方式:
- GET请求:参数附加在URL后,以查询字符串的形式出现,如:example.com?name=value。数据通过URL传输,浏览器会记录访问的URL。
- POST请求:参数包含在请求体(body)中,而不是URL中。数据不会显示在URL中,相对更隐蔽。
- 用途:
- GET请求:用于从服务器获取数据,不会改变服务器的状态。适用于获取资源或数据,例如搜索查询、获取用户信息等。
- POST请求:用于向服务器提交数据,可能会改变服务器的状态。适用于提交表单、上传文件或创建资源。
- 安全性:
- GET请求:因为参数在URL中,容易被浏览器历史记录、服务器日志等记录,不适合传输敏感数据。
- POST请求:参数不在URL中,减少了暴露风险,适合传输敏感数据,但仍需通过HTTPS加密传输以确保数据安全。
- 缓存:
- GET请求:响应可以被浏览器缓存,提高响应速度。
- POST请求:响应通常不会被缓存,确保数据的实时性。
常用类
HttpWebRequest
:发送客户端请求的类
- HttpWebResponse:服务器返回的信息的类
Post请求内容类型
- MIME类型(也称为MIME类型或Content-Type)用于描述传输数据的类型和格式。
- 文本类型
- text/html
- text/css
- text/javascript
- text/plain:用于发送纯文本数据。
This is plain text data.
- 图片类型
- image/gif
- image/png
- image/jpeg
- image/bm
- image/webp
- image/x-icon
- image/vnd.microsoft.icon
- 音频类型
- audio/midi
- audio/mpeg
- audio/webm
- audio/ogg
- audio/wave
- 视频类型
- video/webm
- video/ogg
- 二进制类型(application类型)
- application/octet-stream:通用的二进制类型,常用于文件下载或上传。
- application/x-www-form-urlencoded:用于发送表单数据,数据以键值对形式编码,并通过URL编码特殊字符
- application/json:用于发送JSON格式的数据,适合传输结构化数据。
- application/xml:用于发送XML格式的数据。
name=Tom&age=25
{"name": "Tom","age": 25}
<person><name>Tom</name><age>25</age></person>
- 复合类型(multipart类型)
- multipart/form-data:用于上传文件或二进制数据,请求体以多部分形式编码。
- -boundary
- -boundary--
--boundaryContent-Disposition: form-data; name="field1"value1
Content-Disposition: form-data; name="file"; filename="example.txt"Content-Type: text/plain(file content)
UnityEngine命名空间下的WWW类
WWW
类是Unity提供的用于访问网页的类,可以通过该类下载和上传一些数据。
WWW
类在使用HTTP协议时,默认的请求类型是Get。
- 支持HTTP协议、FTP协议(仅限于匿名下载)、FILE协议(可以异步加载本地文件)。
- 一般配合协同程序使用。
常用方法
常用变量
UnityEngine命名空间下的WWWForm类
WWWFrom
类使用HTTP协议进行上传,用到的请求类型是Post。
常用方法
UnityEngine命名空间下的UnityWebRequest类
UnityWebRequest
是一个Unity提供的模块化的系统类,用于构成HTTP请求和处理HTTP响应
- 主要目的是让Unity客户端与Web服务器进行交互。
- 使用
IMultipartFormSection
接口将数据组合成多部分表单,用于通过UnityWebRequest
将复杂数据序列化成格式正确的字节,以便进行网络请求。
常用方法
DownloadHandler类
DownloadHandlerBuffer
:将下载的数据存储在内存中,适用于简单的数据存储。
DownloadHandlerFile
:将下载的文件直接保存到磁盘,适用于大文件下载。
DownloadHandlerTexture
:下载图像并将其存储为Unity的Texture
对象。
DownloadHandlerAssetBundle
:下载并处理AssetBundle
对象。
DownloadHandlerAudioClip
:下载音频数据并将其存储为AudioClip
对象。
DownloadHandlerScript
:Unity中的一个特殊类,用于处理自定义下载数据;它本身并不执行任何操作,但可以被用户定义的类继承,以便在数据从网络到达时执行完全自定义的数据处理。
UploadHandler类
UploadHandlerRaw
:用于上传字节数组
UploadHandlerFile
:用于上传文件
协议生成工具和ProtoBuf
- 协议生成工具是一种根据通信协议规则自动生成消息定义的工具。它大大降低了维护协议的难度,使得一些协议(例如Protobuf和Thrift)得以流行。
- 协议生成工具的主要作用包括:
- 自动生成消息定义:根据预先设定的协议规则,自动生成消息的定义,减少手动编写的工作量。
- 提高效率:通过自动化生成,减少了人为错误,提高了开发和维护的效率。
- 减少故障:自动生成的消息定义更一致,减少了因手动编写导致的故障。
- 一个典型的
.proto
文件包含以下几个部分: - 语法声明:指定使用 proto3 语法。
- 命名空间声明(可选):避免命名冲突。
- 导入其他
.proto
文件(可选):使用其他文件定义的消息类型。 - 消息类型定义:定义数据结构。
- 枚举类型定义(可选):定义一组命名的整数常量。
- 服务定义(可选):用于 RPC 服务。
- Author:Yuki
- URL:http://shirakoko.xyz/article/note-01
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts