当前位置: 首页 > wzjs >正文

英文网站seo如何做梦创义网站建设

英文网站seo如何做,梦创义网站建设,亚马逊品牌网站建设,市场调研app软件文章目录 1 Disconnect 方法2 心跳消息 ​ 在客户端主动退出时,我们会调用 socket 的 ShutDown() 和 Close() 方法,但调用这两个方法后,服务器端无法得知客户端已经主动断开。 ​ 本文主要介绍在网络通信中,如何服务端如何判断客…

文章目录

  • 1 Disconnect 方法
  • 2 心跳消息

​ 在客户端主动退出时,我们会调用 socket 的 ShutDown()Close() 方法,但调用这两个方法后,服务器端无法得知客户端已经主动断开。

​ 本文主要介绍在网络通信中,如何服务端如何判断客户端断开连接。

1 Disconnect 方法

​ Socket 当中有一个专门在客户端使用的方法:Disconnect 方法。

  • 此方法将结束连接并将 Connected 属性设置为 false。但是,如果 reuseSockettrue,则可以重用套接字。
  • 若要确保在关闭套接字之前发送和接收所有数据,应在调用 Disconnect 方法之前调用 Shutdown。

客户端

​ 在程序退出时,主动断开连接。

public class NetManager : MonoBehaviour
{...public void OnDestroy(){if (_socket != null){Debug.Log("客户端主动断开连接...");_isConnected = false;_socket.Shutdown(SocketShutdown.Both);_socket.Disconnect(false);_socket.Close();_socket = null;}}...
}

服务端

  1. 收发消息时判断 socket 是否已经断开。

    namespace NetLearningTcpServerExercise2;using System.Net.Sockets;public class ClientSocket
    {private static int _ClientBeginId = 1;private Socket _socket;private byte[] _cacheBytes = new byte[1024 * 1024]; // 缓冲区,大小为 1MBprivate int    _cacheBytesLength;public int Id;public bool Connected{get => _socket == null ? false : _socket.Connected;}...public void ReceiveMessage(){if (!Connected) // 判断是否连接{Program.ServerSocket.AddDelSocket(this);return;}try{if (_socket.Available > 0){var buffer        = new byte[1024 * 5];var receiveLength = _socket.Receive(buffer);HandleReceiveMessage(buffer, receiveLength);}}catch (Exception e){Console.WriteLine("ReceiveMessage Wrong: " + e);Program.ServerSocket.AddDelSocket(this); // 解析错误,也认为把消息断开}}...
    }
    
  2. 处理删除记录的 socket 的相关逻辑(使用线程锁)。

namespace NetLearningTcpServerExercise2;using System.Net;
using System.Net.Sockets;public class ServerSocket
{private readonly Socket _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);private Dictionary<int, ClientSocket> _clientSockets = new Dictionary<int, ClientSocket>();private List<ClientSocket> _delList = new List<ClientSocket>(); // 待移除列表private bool _Running;...private void ReceiveMessage(object? state){while (_Running){lock (_clientSockets){if (_clientSockets.Count > 0){foreach (var clientSocket in _clientSockets.Values){clientSocket.ReceiveMessage();}ClearDelSocket(); // 每次循环,检查是否有待移除的 socket}}}}private void ClearDelSocket(){// 移除for (int i = 0; i < _delList.Count; i++){CloseClientSocket(_delList[i]);}_delList.Clear();}public void CloseClientSocket(ClientSocket socket){lock (_clientSockets){Console.WriteLine("ClientSocket Close: " + socket.Id);_clientSockets.Remove(socket.Id);socket.Close();}}public void AddDelSocket(ClientSocket socket){if (!_delList.Contains(socket)){_delList.Add(socket);// Console.WriteLine(socket);}}
}

测试

​ 启动服务器后,运行 Unity 并立刻结束运行,服务器中可以看到如下消息:

image-20250504092837596

2 心跳消息

​ 很多情况下,客户端并不会像上述一样正常断开连接。例如

  1. 非正常关闭客户端时,服务器无法正常收到关闭连接消息。
  2. 客户端长期不发送消息,防火墙或者路由器会断开连接。

​ 因此,在长连接中,客户端和服务端之间会定期发送的一种特殊数据包,用于通知对方自己还在线,以确保长连接的有效性。

​ 由于其发送的时间间隔往往是固定的持续的,就像是心跳一样一直存在,所以我们称之为**“心跳消息”**。

客户端

  1. 定义心跳消息

     public class HeartMessage : INetMessage
    {public int MessageId { get => 999; }public int BytesLength { get => sizeof(int) + sizeof(int); }public byte[] ToBytes(){var length = BytesLength;var bytes  = new byte[length];var index  = 0;index = this.Write(bytes, index, MessageId);// 写入消息长度index = this.Write(bytes, index, length - sizeof(int) * 2); // 减去消息长度和消息 Id 的长度return bytes;}public int FromBytes(byte[] bytes, int index){return index;}
    }
    
  2. 定时发送消息。

    public class NetManager : MonoBehaviour
    {public static NetManager Instance { get; private set; }private Socket _socket;/// <summary>/// 发送消息的公共队列,主线程塞消息,发送线程拿消息进行发送/// </summary>private Queue<INetMessage> _sendMessages = new Queue<INetMessage>();/// <summary>/// 接收消息的公共队列,主线程拿消息,接收线程获取消息塞进去/// </summary>private Queue<INetMessage> _receiveMessages = new Queue<INetMessage>();private bool _isConnected{get => _socket == null ? false : _socket.Connected;}private byte[] _cacheBytes = new byte[1024 * 1024]; // 缓冲区,大小为 1MBprivate int    _cacheBytesLength;private static readonly int _SEND_HEART_MSG_TIME = 2;private void Awake(){Instance = this;// 循环定时给服务端发送心跳消息InvokeRepeating(nameof(SendHeartMsg), 0, _SEND_HEART_MSG_TIME);}public void SendHeartMsg(){if (_isConnected){Send(new HeartMessage());}Debug.Log("发送心跳消息: " + _isConnected);}...
    }
    

服务器

​ 不停检测上次收到某客户端消息的时间,如果超时则认为连接已经断开

namespace NetLearningTcpServerExercise2;using System.Net.Sockets;public class ClientSocket
{private static int _ClientBeginId = 1;private Socket _socket;private byte[] _cacheBytes = new byte[1024 * 1024]; // 缓冲区,大小为 1MBprivate int    _cacheBytesLength;public int Id;private        long _frontTime     = -1; // 上次收到的心跳时间private static int  _TIME_OUT_TIME = 5;public bool Connected{get => _socket == null ? false : _socket.Connected;}public ClientSocket(Socket socket){Id      = _ClientBeginId++;_socket = socket;ThreadPool.QueueUserWorkItem(CheckTimeOut, null);}/// <summary>/// 间隔一段时间检测超时/// </summary>/// <param name="state"></param>private void CheckTimeOut(object? state){while (Connected){if (_frontTime != -1 &&DateTime.Now.Ticks / TimeSpan.TicksPerSecond - _frontTime > _TIME_OUT_TIME){Program.ServerSocket.AddDelSocket(this);break;}Thread.Sleep(1000);}}public void Close(){if (_socket != null){_socket.Shutdown(SocketShutdown.Both);_socket.Close();_socket = null!;}}public void SendMessage(INetMessage message){if (!Connected){Program.ServerSocket.AddDelSocket(this);return;}try{_socket.Send(message.ToBytes());}catch (Exception e){Console.WriteLine("SendMessage Wrong: " + e);Program.ServerSocket.AddDelSocket(this);}}public void ReceiveMessage(){if (!Connected){Program.ServerSocket.AddDelSocket(this);return;}try{if (_socket.Available > 0){var buffer        = new byte[1024 * 5];var receiveLength = _socket.Receive(buffer);HandleReceiveMessage(buffer, receiveLength);}}catch (Exception e){Console.WriteLine("ReceiveMessage Wrong: " + e);Program.ServerSocket.AddDelSocket(this); // 解析错误,也认为把消息断开}}private void MessageHandle(object? state){if (state == null) return;var msg = (INetMessage) state;if (msg is PlayerMessage playerMsg){Console.WriteLine($"Receive message from client {_socket} (ID {Id}): {playerMsg}");}else if (msg is QuitMessage quitMsg){Program.ServerSocket.AddDelSocket(this); // 客户端断开连接}else if (msg is HeartMessage heartMsg){_frontTime = DateTime.Now.Ticks / TimeSpan.TicksPerSecond;Console.WriteLine($"Receive heart message from client {_socket} (ID {Id}): {heartMsg}");}}private void HandleReceiveMessage(byte[] receiveBytes, int receiveNum){var messageId = 0;var index     = 0;// 收到消息时看之前有没有缓存// 如果有,直接拼接到后面receiveBytes.CopyTo(_cacheBytes, _cacheBytesLength);_cacheBytesLength += receiveNum;while (true){var messageLength = -1;// 处理前置信息if (_cacheBytesLength - index >= 8){// 解析 IdmessageId =  BitConverter.ToInt32(_cacheBytes, index);index     += sizeof(int);// 解析长度messageLength =  BitConverter.ToInt32(_cacheBytes, index);index         += sizeof(int);}// 处理消息体if (messageLength != -1 && _cacheBytesLength - index >= messageLength){// 解析消息体INetMessage message = default;switch (messageId){case 1001:message = new PlayerMessage();message.FromBytes(_cacheBytes, index);break;case 1003:message = new QuitMessage();message.FromBytes(_cacheBytes, index);break;case 999:message = new HeartMessage();message.FromBytes(_cacheBytes, index);break;}if (message != default){ThreadPool.QueueUserWorkItem(MessageHandle, message);}index += messageLength;// 如果消息体长度等于缓存长度,证明缓存已经处理完毕if (index == _cacheBytesLength){_cacheBytesLength = 0;break;}}else // 消息体还没有接收完毕{// 解析了前置信息,但是没有成功解析消息体if (messageLength != -1){index -= 8; // 回退到解析 Id 的位置}// 缓存剩余的数据_cacheBytesLength -= index;Array.Copy(_cacheBytes, index, _cacheBytes, 0, _cacheBytesLength);break;}}}
}

测试

​ 启动服务器后,运行 Unity,服务器中可以定时收到心跳消息:

image-20250504093828255

​ 结束运行 Unity,等待 5s 后,可看到服务器显示断开连接:

image-20250504095602541
http://www.dtcms.com/wzjs/571342.html

相关文章:

  • 网站改版 建设方案怎么创建免费的个人网站
  • 网站建好了 怎么建后台重庆vr制作
  • 四川网站seo设计做自己域名的网站很贵吗
  • 网站 keywords做网站和seo哪个好
  • 做画册好的网站企业网站开发目的和意义
  • 个人网站赚钱长沙官网网站建设哪家好
  • 建设部网站官网施工合同文本微信网站开发登录
  • 泉州模板建站平台西安 做网站
  • 网站建设难不难专业网页制作服务商
  • 网站首页策划怎么做如何做网站推广获客
  • 如何接单做网站营销型网站页面摸板
  • 设计网站属于什么专业上海上市装修公司
  • 上海市嘉定建设局网站基金公司网站建设方案
  • 淘宝客户自己做网站怎么做新网站如何做百度百科
  • 在线做简历的网站wordpress使用七牛图像服务
  • 做电力 公司网站做网站建设费用预算
  • 网站外包如何报价免费样机素材网站
  • 电子产品网站建设策划方案php可以自己做网站吗
  • 联通公司网站谁做的长春网站排名优化
  • wordpress 哪些网站吗呼市网站制作
  • 申请网站建设费大连 响应式网站
  • 做网站需要的技术 规范抚州市建设局网站查询
  • 网页模板下载网站10wordpress 修改小工具样式
  • 中国建设网官方网站平台wordpress 内容字段
  • 公司如何做网站建设四川水利工程造价信息网
  • 大型网站建设规范做一下网站收购废钢
  • 长春市住房建设局网站外贸网站能用阿里云吗
  • 在哪里能建免费的网站网站外链建设原则
  • 个人网站做电影网站360网站建设的目标是什么
  • 网站突然显示 建设中推广专员