连接收发消息流程
服务端
//启动类
class Program
{
static void Main(string[] args)
{
//启动程序中创建一个Server类,传入ip和端口
Server server = new Server("127.0.0.1", 6688);
server.Start();
Console.ReadKey();
}
}
//初始化Server
public Server(string ipStr,int port)
{
//创建一个controllerManager管理类,用于管理不同类型的消息和动作的controllerManager类
controllerManager = new ControllerManager(this);
//设置服务器IP和端口
SetIpAndPort(ipStr,port);
}
//设置需要连接的IP和端口
public void SetIpAndPort(string ipStr,int port)
{
//创建一个IP对象
ipEndPoint = new IPEndPoint(IPAddress.Parse(ipStr), port);
}
//创建Socket类
public void Start()
{
//创建一个socket对象
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);
//绑定ip和端口
serverSocket.Bind(ipEndPoint);
//开启最大监听数,0表示没有限制
serverSocket.Listen(0);
//开始接受连接
serverSocket.BeginAccept(AcceptCallBack,null);
}
//收到连接的回调
private void AcceptCallBack(IAsyncResult ar)
{
//得到一个客户端的连接
Socket clientSocket = serverSocket.EndAccept(ar);
//创建服务端的一个Client与客户端对应,并且将clientSocket传入,用于消息的收发
Client client = new Client(clientSocket,this);
//初始化客户端
client.Start();
//将连接的客户端增加到list中进行管理
clientList.Add(client);
//继续开始下一个连接的监听
serverSocket.BeginAccept(AcceptCallBack,null);
}
//Client类
public void Start()
{
if(clientSocket==null ||clientSocket.Connected==false)
{
return;
}
//开启消息的监听,设置消息接收的回调
clientSocket.BeginReceive(msg.Data, msg.StartIndex, msg.RemainSize, SocketFlags.None,ReceviceCallBack,null);
}
//Client类中消息接收
private void ReceviceCallBack(IAsyncResult ar)
{
try
{
if ( clientSocket == null || clientSocket.Connected == false)
{
return;
}
int count = clientSocket.EndReceive(ar);
if (count == 0)
{
Close();
}
//处理接收到的数据,这里的处理和客户端接收到消息后一致(客户端写的比较详细)
msg.ReadMessage(count,OnProcessMessage);
Start();
//clientSocket.BeginReceive(null, 0, 0, SocketFlags.None, ReceviceCallBack, null);
}
catch(Exception e)
{
Console.WriteLine(e);
Close();
}
}
//创建一个解析完消息的回调函数,Client类中的
private void OnProcessMessage(RequestCode requestCode,ActionCode actionCode,string data)
{
server.HandleRequest(requestCode, actionCode, data, this);
}
//Server类中的
public void HandleRequest(RequestCode requestCode, ActionCode actioncode, string data, Client client)
{
//通过controllerManager调用不同的controllerManager类来处理不同的请求和动作
controllerManager.HandleRequest(requestCode, actioncode, data, client);
}
//controllerManager类中的
public void HandleRequest(RequestCode requestCode,ActionCode actionCode,string data,Client client)
{
BaseController controller;
//通过requestCode找到不同的controller类
bool isGet = controllerDict.TryGetValue(requestCode, out controller);
if(isGet == false)
{
Console.WriteLine("无法得到" + requestCode + "所对应的Controller,无法处理请求");
return;
}
//通过actionCode找到对应的方法名
string methodName = Enum.GetName(typeof(ActionCode), actionCode);
//根据得到的controller类和methodName得到方法
MethodInfo mi = controller.GetType().GetMethod(methodName);
if(mi == null)
{
Console.WriteLine("[警告]在Controller[" + controller.GetType() + "]中没有对应的处理方法:[" + methodName + "]");
}
//创建一个参数类型,参数中包含了数据,客户端,服务端
object[] parameters = new object[] { data,client,server };
//调用对应controller类中的对应方法,传入参数,得到处理后的结果
object o = mi.Invoke(controller, parameters);
if (o == null || string.IsNullOrEmpty(o as string))
{
Console.WriteLine("return 掉了吗");
return;
}
//通过Server统一回复消息给客户端
server.SendResponse(client, actionCode, o as string);
}
//sever中的类
//这个函数是controllerManager处理完消息后,调用此方法,发送消息给客户端
public void SendResponse(Client client,ActionCode actionCode,string data)
{
//通过形参调用对应的client进行消息的发送
client.Send(actionCode, data);
}
- 创建一个Server对象
- 将IP和端口作为参数传入
- 创建一个ControllerManager类,用于对不同类型的controller进行管理
- 根据传入的IP和端口创建一个IP对象
- 创建一个Socket对象,绑定IP对象开启连接监听。设置连接后的回调函数
- 连接后,创建一个与客户端对应的client,将socket对象和自身传入,用于后续消息的收发,将client放到list中进行管理
客户端(MVC)
//创建一个GameFacade类,继承自MonoBehaviour
public class GameFacade : MonoBehaviour {
//Awake中设置分辨率
private void Awake()
{
Screen.SetResolution(1280, 800, false);
}
void Start ()
{
//初始化各种管理类
InitManager();
}
private void InitManager()
{
//UI框架类
uiManager = new UIManager(this);
//相机类,用于显示和跟随
cameraManager = new CameraManager(this);
//音效类
audioManager = new AudioManager(this);
//玩家类
playerManager = new PlayerManager(this);
//消息类
requestManager = new RequestManager(this);
//客户端管理类
clientManager = new ClientManager(this);
//各个Manager类进行初始化
uiManager.OnInit();
cameraManager.OnInit();
audioManager.OnInit();
playerManager.OnInit();
requestManager.OnInit();
clientManager.OnInit();
}
//用于对每个管理类进行update
void Update()
{
UpdateManager();
if(isEnterPlay)
{
EnterPlaying();
isEnterPlay = false;
}
}
}
//与服务端的连接主要是ClientManager中
//定义IP和端口
private const string IP = "127.0.0.1";
private const int PORT = 6688;
//消息对象,用于对消息的解析
private Message msg = new Message();
//对ClientManager进行初始化
public override void OnInit()
{
//调用基类的初始化函数
base.OnInit();
//创建一个Socket连接
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
//连接服务器
clientSocket.Connect(IP, PORT);
Start();
}
catch(Exception e)
{
Debug.LogWarning("无法连接到服务器端,清检查你的网络!!" + e);
}
}
private void Start()
{
//开启消息的监听,将消息存入之前定义的msg,得到内容,开始index,
clientSocket.BeginReceive(msg.Data,msg.StartIndex,msg.,SocketFlags.None,ReceiveCallback,null);
}
//接收到消息的回调,这个不是在主线程中,需要访问unity的组件什么的,需要在主线程访问
private void ReceiveCallback(IAsyncResult ar)
{
//Debug.LogWarning("接收到一条数据:");
try
{
if(clientSocket==null ||clientSocket.Connected==false)
{
return;
}
//获取消息的长度
int count = clientSocket.EndReceive(ar);
//读取消息内容
msg.ReadMessage(count, OnProcessDataCallback);
Start();
}catch(Exception e)
{
Debug.Log(e);
}
}
//消息类的读取消息函数
//解析数据,客户端解析数据没有actionCode,服务端只会传消息号和内容。
public void ReadMessage(int newDataAmount, Action<ActionCode, string> processDataCallBack)
{
startIndex += newDataAmount;
while (true)
{
if (startIndex <= 4)
{
return;
}
//解析出数据总长,int数据类型
int count = BitConverter.ToInt32(data, 0);
if ((startIndex - 4) >= count)
{
//解析出requesCode,这里的actionCode 类型是枚举类型,用 as 方式转型不行,采用强制转型的方式。
ActionCode actionCode = (ActionCode)BitConverter.ToInt32(data, 4);
//解析出数据
string s = Encoding.UTF8.GetString(data, 8, count - 4);
if(actionCode!=ActionCode.Move)
{
Console.WriteLine("解析出来一条数据:" + actionCode + s);
}
//触发回调,传入动作类型和数据
processDataCallBack(actionCode, s);
Array.Copy(data, count + 4, data, 0, startIndex - 4 - count);
startIndex -= (count + 4);
}
else
{
break;
}
}
}
private void OnProcessDataCallback(ActionCode actionCode,string data)
{
//调用facade的HandleReponse函数对消息进行统一的处理
facade.HandleReponse(actionCode, data);
}
//gamefacade类中的函数
public void HandleReponse(ActionCode actionCode, string data)
{
//调用requestManager中的HandleReponse方法,根据传入的actionCode来调用对应类中的方法
requestManager.HandleReponse(actionCode, data);
}
//requestManager中的类
public void HandleReponse(ActionCode actionCode,string data)
{
//从字典中找到对应的类
BaseRequest request = requestDict.TryGet<ActionCode,BaseRequest>(actionCode);
if(actionCode!=ActionCode.Move)
{
Debug.LogWarning("接收一条消息:\n" + "动作:" + actionCode + " 数据:" + data);
}
if (request == null)
{
Debug.LogWarning("无法得到ActionCode[" + actionCode + "]对应的方法");
return;
}
//调用对应类的OnResponse函数
request.OnResponse(data);
}
//以ShowTimerRequest为例
public override void OnResponse(string data)
{
int time = int.Parse(data);
//界面根据服务端数据返回进行展示
gamePanel.ShowTimeSync(time);
}