网络游戏是一种人们娱乐休闲互交的应用软件。既然是互交,当然需要彼此间的了解通讯。要通讯那必须需要Socket:我们今天要实现的主角即套接字。Socket的英文原义是“孔”或“插座”,正如其英文原意那样,象一个多孔插座。一台电脑机器犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。下面我们来看看下图,游戏中玩家移动是如何通讯:
下面是Unity3d游戏通讯Socket实现: BaseGameSocket.cs
@原创:dongfu.luo
using System;
using System.Collections.Generic;
using System.Net.Sockets;
public abstract class BaseGameSocket
{
//用来接收服务端发过来的缓冲Buff
private byte[] _data_buffer;
//缓冲二进制数组从哪里开始读
private int _data_offset;
//缓冲二进制数组读多少个byte
private 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;
//清空数据,一般是在断开重联时候调用
{
//用来接收服务端发过来的缓冲Buff
private byte[] _data_buffer;
//缓冲二进制数组从哪里开始读
private int _data_offset;
//缓冲二进制数组读多少个byte
private 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
{
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"));
}
}
//连接游戏服务端
{
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没有关闭继续等服务器信息,如果有信息则开始读
{
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"));
}
}
//从发送队列从不断向游戏服务器发送命令
{
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一般是网络断了服务器关闭了
{
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);
}
//程序猿都知道这是析构函数
{
this.Close();
this.OnError(msg);
}
//程序猿都知道这是析构函数
~PackedSocket()
{
this.Close();
}
{
this.Close();
}
public int GetSendQueueSize()
{
List<PacketOut> list = this._send_list;
lock (list)
{
return this._send_list.Count;
}
}
//此函数由子类去处理
{
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)
{
//如果是第一次连接上了,解析消息头
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)
{
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();
}
}
//读取消息体
{
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();
}
//读取消息头
{
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();
}
//具体的发送信息,先把数据发到发送队列
{
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)
{
{
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();
}
}
}
{
this.ContinueSend();
}
}
}
public bool IsClosed
{
get
{
return (this._sock == null);
}
}
{
get
{
return (this._sock == null);
}
}
public bool IsConnected
{
get
{
return ((this._sock != null) && this._sock.Connected);
}
}
{
get
{
return ((this._sock != null) && this._sock.Connected);
}
}
private class PacketOut
{
public byte[] buff;
public Socket sock;
public bool start;
}
}
{
public byte[] buff;
public Socket sock;
public bool start;
}
}
相关推荐
Unity3D是一款强大的跨平台游戏开发引擎,广泛应用于游戏制作、虚拟现实(VR)、增强现实(AR)等领域。...通过学习和实践,你可以熟练掌握Unity3D中的网络通讯,为你的游戏或应用提供稳定高效的网络功能。
在Unity3D中进行Socket通信是开发网络游戏或实时交互应用时不可或缺的一部分。Socket通信允许Unity3D客户端与服务器之间建立连接,发送和接收数据。在本文中,我们将深入探讨Unity3D中的Socket通信,主要基于给出的...
总之,Android Studio与Unity3D的Socket通讯是跨平台应用开发中的关键技术,通过理解TCP/IP协议、Socket编程以及Android和Unity3D的API,开发者可以实现高效、稳定的数据交换,为用户提供丰富的互动体验。
总的来说,《Unity3D网络游戏书》是一本全面覆盖C#编程、Unity引擎应用、Socket网络编程以及网络游戏服务器设计的教程。无论你是希望入门网络游戏开发,还是希望提升现有技能,都能从这本书中找到你需要的知识。通过...
在IT行业中,Unity3D是一款广泛应用...总结,Unity3D结合Protobuf和Socket通信,可以实现高效、低延迟的网络交互,适用于对实时性和性能要求较高的场景。通过这种方式,开发者可以构建出更加灵活、高效的网络应用程序。
在Unity3D网络通信中,异或加密是一种简单但有效的保护数据安全的方法。异或加密的基本原理是对两个二进制位进行异或操作,相同结果为0,不同结果为1。异或具有自逆性,即同一个密钥对数据加密后,再用该密钥解密,...
在某些场景下,我们可能需要在Unity的3D环境和Winform的界面之间进行数据交互,这时可以利用Socket编程实现两者之间的通信。Socket是一种网络通信协议,它允许两个网络应用之间通过TCP/IP协议进行双向通信。 首先,...
在Unity3D中,Socket编程主要用于实现游戏中的网络通信,例如玩家之间的交互、游戏状态同步等。本教程主要讲解了如何使用Socket进行TCP协议的通信,分为服务端(Server)和客户端(Client)两部分。 首先,我们来看...
在Unity3D开发过程中,网络通信是一项非常重要的功能,而Socket编程则是实现这一功能的基础之一。然而,在使用Socket进行网络通信时,经常会遇到安全策略的问题,尤其是在使用WebPlayer发布游戏时。本文将详细介绍...
本话题主要聚焦于Unity3D与Java之间的Socket通信,这是一种网络通信协议,允许两个应用程序通过网络进行双向数据传输。 首先,理解Socket通信的基础原理至关重要。Socket是网络编程中的一个接口,它提供了进程间...
3.发送游戏事件。 4.以二进制方式发送网络消息。 5.以ProtuBuf方式发送网络消息。 Server.cs 功能: 1.收到的数据不做修改即可发送 目录说明: 1.Scripts/Socket/Protobuf:Protobuf源码 2.Scripts/Socket/...
总的来说,这个Unity3D五子棋网络版源码是一个很好的学习资源,它涵盖了Unity3D的游戏逻辑实现、网络通信机制、以及多玩家同步游戏的关键技术。无论是初学者还是有经验的开发者,都可以从中学习到如何在Unity3D环境...
标题:“unity3d网络五子棋的服务器端” 这个项目旨在创建一个能够支持多玩家在线对战的五子棋游戏服务器。服务器端通常负责处理客户端(玩家)的连接请求、游戏状态同步以及数据存储。Unity3D是一个流行的跨平台...
在Unity3D中,有时候开发者需要实现实时的数据通信,例如玩家之间的交互或者服务器推送的游戏状态更新,这时WebSocket协议就显得尤为重要。WebSocket是一种在客户端和服务器之间建立持久性连接的协议,提供全双工...
通过比较使用和不使用IOCP模型的通信方式,可以明显看出IOCP在高并发网络游戏中带来的性能提升。 在系统需求分析中,用户功能需求包括游戏界面、操作方式、匹配系统和聊天功能等。系统性能要求考虑了响应速度、稳定...
"Unity3D基于Socket通讯的公共聊天室实现" 本篇教程旨在指导初学者实现一个基于 Socket 通讯的公共聊天室,使用 Unity3D 和 C# 语言。这个实例将向初学者提供指导意义,帮助他们更好地理解网络游戏开发的基础知识。...
在本项目中,我们关注的是一个使用C#编程语言和Unity3D引擎开发的网络角色扮演游戏(MMORPG)的本科毕业设计。这个设计涵盖了游戏开发的多个关键方面,包括客户端、服务器端以及两者之间的通信机制。以下是这个项目...
在Unity3D中,Socket是用于网络通信的重要组件,它允许游戏对象与其他设备或服务器进行数据交换。在本文档的上下文中,我们看到一个名为`TestAsyncSocketClient2`的类,该类展示了如何在Unity3D中实现异步TCP Socket...