网络游戏是一种人们娱乐休闲互交的应用软件。既然是互交,当然需要彼此间的了解通讯。要通讯那必须需要Socket:我们今天要实现的主角即套接字。Socket的英文原义是“孔”或“插座”,正如其英文原意那样,象一个多孔插座。一台电脑机器犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。下面我们来看看下图,游戏中玩家移动是如何通讯:

下面是Unity3d游戏通讯Socket实现: BaseGameSocket.cs

//@原创:dongfu.luo
using System;
using System.Collections.Generic;
using System.Net.Sockets;
public abstract class BaseGameSocket
{//用来接收服务端发过来的缓冲Buffprivate byte[] _data_buffer;//缓冲二进制数组从哪里开始读private int _data_offset;//缓冲二进制数组读多少个byteprivate int _data_size;//游戏服务器IP地址private string _ip;private bool _is_read_head;//游戏服务器端口private int _port;//要服务端发送的数据命令列表private List<PacketOut> _send_list = new List<PacketOut>();private Socket _sock;private const int MAX_SEND_QUEUE = 0x3e8;//清空数据,一般是在断开重联时候调用 private void Clear(){this._ip = null;this._port = 0;this._sock = null;List<PacketOut> list = this._send_list;lock (list){this._send_list.Clear();}this._is_read_head = false;this._data_buffer = null;this._data_offset = 0;this._data_size = 0;}//关闭客户端的Socket public void Close(){try{Socket socket = this._sock;this.Clear();if ((socket != null) && socket.Connected){socket.Shutdown(SocketShutdown.Both);socket.Close();}}catch (Exception exception){UEDebug.LogError("Connect: " + exception.ToString());this.Error(Lang.GetString("k3432"));}}//连接游戏服务端
public void Connect(string ip, int port){try{this.Close();this._ip = ip;this._port = port;this._sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);this._sock.NoDelay = true;this._sock.BeginConnect(this._ip, this._port, new AsyncCallback(this.OnConnect), this._sock);}catch (Exception exception){UEDebug.LogError("Connect: " + exception.ToString());this.Error(Lang.GetString("k3432"));}}//如果Socket没有关闭继续等服务器信息,如果有信息则开始读 private void ContinueRead(){try{if (this.IsConnected){
this._sock.BeginReceive(this._data_buffer, this._data_offset, this._data_size - this._data_offset, SocketFlags.None, new AsyncCallback(this.OnRead), null);}}catch (Exception exception){UEDebug.LogError(exception.ToString());this.Error(Lang.GetString("k3432"));}}//从发送队列从不断向游戏服务器发送命令 private void ContinueSend(){PacketOut state = null;List<PacketOut> list = this._send_list;lock (list){if (this._send_list.Count == 0){return;}state = this._send_list[0];if (state.start){return;}state.start = true;}Socket sock = state.sock;if (sock.Connected){sock.BeginSend(state.buff, 0, state.buff.Length, SocketFlags.None, new AsyncCallback(this.OnSend), state);}}
//发送失败或错误,则关闭Socket一般是网络断了服务器关闭了 protected void Error(string msg){this.Close();this.OnError(msg);}//程序猿都知道这是析构函数 ~PackedSocket(){this.Close();}public int GetSendQueueSize(){List<PacketOut> list = this._send_list;lock (list){return this._send_list.Count;}}//此函数由子类去处理 protected abstract void OnConnect();//如果是第一次连接上了,解析消息头private void OnConnect(IAsyncResult ret){if (ret.AsyncState == this._sock){try{this._sock.EndConnect(ret);this.ReadHead();this.OnConnect();}catch (Exception exception){Debug.log(exception);}}}protected abstract void OnError(string msg);protected abstract void OnPack(byte[] data);//有服务端信息来,开始解析,现解析信息头再解析消息体private void OnRead(IAsyncResult ar){try{if (this.IsConnected){int num = this._sock.EndReceive(ar);this._data_offset += num;if (num <= 0){}else if (this._data_offset != this._data_size){this.ContinueRead();}else if (this._is_read_head){int num2 = BitConverter.ToInt32(this._data_buffer, 0);this.ReadData(num2);}else{this.OnPack(this._data_buffer);this.ReadHead();}}}catch (Exception exception){Debug.log(exception);}}//如果命令发送成功,检查发送队列是否还有需要发送的命令。如果有则继续发送 private void OnSend(IAsyncResult ar){PacketOut asyncState = ar.AsyncState as PacketOut;Socket sock = asyncState.sock;if (sock.Connected){sock.EndSend(ar);List<PacketOut> list = this._send_list;lock (list){if (this._send_list.Contains(asyncState)){this._send_list.Remove(asyncState);}}this.ContinueSend();}}
//读取消息体 private void ReadData(int pack_len){this._is_read_head = false;this._data_size = pack_len;this._data_offset = 4;this._data_buffer = new byte[this._data_size];this.ContinueRead();}//读取消息头 private void ReadHead(){this._is_read_head = true;this._data_size = 4;this._data_offset = 0;this._data_buffer = new byte[this._data_size];this.ContinueRead();}//具体的发送信息,先把数据发到发送队列 public void Send(byte[] buff)
{if (this.IsConnected){PacketOut item = new PacketOut {start = false,buff = buff,sock = this._sock};int count = 0;List<PacketOut> list = this._send_list;lock (list){this._send_list.Add(item);count = this._send_list.Count;}if (count > 0x3e8){}else{this.ContinueSend();}}}public bool IsClosed{get{return (this._sock == null);}}public bool IsConnected{get{return ((this._sock != null) && this._sock.Connected);}}
private class PacketOut{public byte[] buff;public Socket sock;public bool start;}
}

Unity3d网络游戏Socket通讯相关推荐

  1. GJM: Unity3D基于Socket通讯例子 [转载]

    首先创建一个C# 控制台应用程序, 直接服务器端代码丢进去,然后再到Unity 里面建立一个工程,把客户端代码挂到相机上,运行服务端,再运行客户端. 高手勿喷!~! 完全源码已经奉上,大家开始研究吧! ...

  2. Linux网络服务器epoll模型的socket通讯的实现(一)

    准备写一个网络游戏的服务器的通讯模块,参考网上看到的一些代码,在linux下面实现一个多线程的epoll模型的socket通讯的代码,以下是第一部分多线程的切换代码: 1 #include <s ...

  3. 《Unity3D网络游戏实战》第7章

    <Unity3D网络游戏实战>第7章 服务端架构 总体架构 模块划分 游戏流程 Json编码解码 添加协议文件 引用System.web.Extensions 修改MsgBase类 测试 ...

  4. Unity3D 网络游戏框架(一、网络基础)

    1.套接字(Socket)         网络上两个程序通过一个双向的通信连接实现数据交换,这个连接的一端称为一个Socket.一个Socket包含了进行网络通信必须的五种信息:连接使用的协议.本地 ...

  5. Unity3D网络游戏开发——开始网络编程:Echo

    Unity3D网络游戏开发--开始网络编程:Echo(客户端部分) 什么是Echo程序 Echo程序是网络编程中最基础的案例.建立网络连接后,客户端向服务端发送一行文本,服务端收到后将文本送回客户端. ...

  6. Unity3D网络游戏0.1

    一.网络游戏的架构 (1)网络游戏:   分为客户端和服务端两个部分,客户端程序运行在用户的电脑或手机上,服务端程序运行在游戏运营商的服务器上.   以下是一些典型的游戏客户端.            ...

  7. Java与C++Socket通讯注意

    2019独角兽企业重金招聘Python工程师标准>>> c++与java进行socket通信时注意事项 因为java发送的都是网络字节序(big-endium),而c++是主机字节序 ...

  8. [置顶] 【C#】 Socket通讯客户端程序

    这段时间一直在优化Socket通讯这块,经常和Socket打交道,现在分享给大家一个小的案例, 代码如下: byte[] m_dataBuffer = new byte [10];         I ...

  9. java与 C++ 之间进行 SOCKET 通讯要点简要解析

    Endian定义: 在计算机系统体系结构中用来描述在多字节数中各个字节的存储顺序. big-endian也称高位在前.大端在前.是 计算机体系结构中一种描述多字节存储顺序的术语,在这种机制中最重要字节 ...

最新文章

  1. rommon模式下给路由器灌入IOS
  2. 如何禁用请求库中的日志消息?
  3. 基于RTP的h.264视频传输系统(二)
  4. 【转载】用 Pyinstaller 来打包 + 解决打包结果过大问题
  5. 完全背包问题从简单到复杂
  6. [蓝桥杯][算法提高VIP]凶手-思维
  7. 网络——获取Web数
  8. 张平文当选美国工业与应用数学学会会士
  9. 解析函數論 Page 28 連續復變函數的最簡單的性質
  10. 485. 最大连续1的个数
  11. 【学习总结】GirlsInAI ML-diary day-7-数据类型转换
  12. 【模型压缩】Only Train Once:微软、浙大等研究者提出剪枝框架OTO,无需微调即可获得轻量级架构...
  13. 07-12-Exchange Server 2019-安装-CU1
  14. 《xxx重大需求征集系统的》可用性和可修改性战术分析
  15. Redis源码学习(11),t_hash.c 学习(二),hget 相关命令学习
  16. 知识产权服务代理行业税收政策
  17. NOIP2012 模拟试题二 腾讯大战360
  18. Python str 模块
  19. Activiti7工作流引擎:进阶篇(八) 会签
  20. 关于二分查找那些事儿~~~~看完至少节省你两个半月的时间!!!!!

热门文章

  1. python基础 python函数 函数概念 函数的多种参数 多种调用参数 装包 解包 函数代码块 函数的返回值
  2. esp8266显示农历
  3. dataframe选取特定行和列
  4. 傅里叶变换--虚部的理解
  5. 计算机管理员权限win8,Win8怎么取得管理员权限?
  6. mybatis下载地址
  7. 阿里云ACP考试模拟试题(3)
  8. git .git目录提交_压扁Git提交
  9. 8个暴笑幽默及顿悟的哲理故事
  10. 负载均衡算法WRR介绍