NetworkManager网络通讯_破产版NetworkManager(五)
根据对NetWorkServer 以及NetworkClient的理解,编写一个简易版的NetWork Manager。惯例全部代码放在最后
(一)NetWorkServer与NetworkClient机制
网络中一个Server对应对各client,unet NetWorkServer主要为静态方法,通过绑定ip地址以及端口就可以监听连接,client通过connect进行连接,当连接成功后通过注册的相关消息进行连接成功与否的方法进行相应处理(采用socket编程时一般通过回调俩进行处理,在unet中稍有不同,但原理一样)
1)server进行监听,并注册监听事件
代码如下:
NetworkServer.Listen(ip, port);
NetworkServer.RegisterHandler(MsgType.Connect, OnServerConnect);
NetworkServer.RegisterHandler(MsgType.Disconnect, OnServerDisconnect);//如果stopServer则不会触发此事件,只有客户端主动断开连接(stopclient)时触发
NetworkServer.RegisterHandler(MsgType.AddPlayer, OnServerAddPlayer);
NetworkServer.RegisterHandler(MsgType.RemovePlayer, OnServerRemovePlayer);
NetworkServer.RegisterHandler(CustomerMsgType.StringMsg, OnServerReceiveStringMsg);
上述RegisterHandler注册的监听事件中前四个为unet自定义消息类型,以MsgType.Connect为例,根据变量名字可知当server在MsgType.Connect注册OnServerConnect方法,当client端连接到server端时,server端会调用OnServerConnect方法。unet允许自定义消息类型,如NetworkServer.RegisterHandler(CustomerMsgType.StringMsg, OnServerReceiveStringMsg); 自定义消息类型CustomerMsgType.StringMsg(short类型)不能与unet自定义的消息类型冲突。client端要注册相对应的消息类型
2)client进行连接,并注册事件
unetClient = new NetworkClient();
RegisterClientMessage(unetClient);
unetClient.Connect(ip, port);
void RegisterClientMessage(NetworkClient client)
{
client.RegisterHandler(MsgType.Connect, OnClientConnect);
client.RegisterHandler(MsgType.Disconnect, OnClientDisconnect);//服务端主动断开或者stopServer时触发,但客户端主动断开连接(stopClient)时不会触发
client.RegisterHandler(CustomerMsgType.StringMsg, OnClientReceiveStringMsg); if (localPlayer!=null)
{
ClientScene.RegisterPrefab(localPlayer);
}
}
(二)clientScene场景管理
通过上一步,实现了Server与client的连接,一个client与server连接成功后对应一个networkconnection,通过连接绑定相应的游戏物体来进行操作则需要clientScene。clientScene组要为静态方法,统一管理连接的游戏物体。
1)当客户端接收到连接成功后在OnClientConnect创建游戏物体(可以自己手动代码创建,但是unet已经为我们组好处理,直接调用即可)
NetworkConnection conn = msg.conn;
ClientScene.Ready(conn); CustomerMsgType.StringMessage stringMsg = new CustomerMsgType.StringMessage();
stringMsg.stringMsg = "ttt";
ClientScene.AddPlayer(conn, (short)conn.connectionId, stringMsg);
2)连接成功后通过clientScene添加玩家(AddPlayer),调用后会激发服务端注册的OnServerAddPlayer方法( NetworkServer.RegisterHandler(MsgType.AddPlayer, OnServerAddPlayer);)然后生成服务端游戏物体
void OnServerAddPlayer(NetworkMessage msg)
{
//var message = msg.ReadMessage<CustomerMsgType.StringMessage>();
//Debug.Log(message.stringMsg);
var player = Instantiate(localPlayer);
msg.ReadMessage(addPlayerMsg);
//Debug.Log(Encoding.Default.GetString(addPlayerMsg.msgData));
NetworkServer.AddPlayerForConnection(msg.conn, player, addPlayerMsg.playerControllerId); LogInfo.theLogger.Log("Client "+msg.conn.connectionId+" is added");
}
(三)前两步梳理
1)服务端开启监听
2)客户端连接
3)连接后客户端向clientscene添加玩家
4)服务端接收到玩家添加成功的消息,并创建玩家
(四)消息发送
客户端服务端发送消息时,要先注册消息类型以及对应的方法,通过NetworkClient的send方法以及NetworkServer的send方进行发送。
1)注册消息
如步骤(一)中的client.RegisterHandler(CustomerMsgType.StringMsg, OnClientReceiveStringMsg)(客户端) NetworkServer.RegisterHandler(CustomerMsgType.StringMsg, OnServerReceiveStringMsg)(服务端)
2)消息的发送
public void Send(string msg)
{
CustomerMsgType.StringMessage stringMsg = new global::CustomerMsgType.StringMessage();
stringMsg.stringMsg = msg; unetClient.Send(CustomerMsgType.StringMsg, stringMsg);
}
向服务端发送消息,发送时包含发送的消息主体stringMsg(为继承MessageBase的类型)以及发送消息的类型CustomerMsgType.StringMsg
3)通过NetworkMessage进行消息读取
所有注册的消息对应的方法都含有一个NetworkMessage参数,它包含此次操作 对应的networkconnection以及传递过来的消息,消息的读取如下所示
void OnServerReceiveStringMsg(NetworkMessage msg)
{
var receivedMsg = msg.ReadMessage<CustomerMsgType.StringMessage>();
//var newMsg = "Server received:" + receivedMsg.stringMsg; LogInfo.theLogger.Log(receivedMsg.stringMsg); var message = new CustomerMsgType.StringMessage();
message.stringMsg = "Server received:" + receivedMsg.stringMsg ;
NetworkServer.SendToClient(lastClient.connectionId, CustomerMsgType.StringMsg, message);
}
服务端端向客端发送时,除了要输入发送的类型CustomerMsgType.StringMsg以及发送的消息message外还要指定发送的客户端IDlastClient.connectionId。此为消息发送的整个流程。也可以通过networkReader和networkWriter进行消息的发送与读取
//-------------------------------------------代码--------------------------------------------//
主代码:
using UnityEngine;
using UnityEngine.Networking;
using System;
using UnityEngine.Networking.NetworkSystem;
using System.Collections.Generic;
using System.Text; public class MyNetworkManager : MonoBehaviour
{
public string ip = "127.0.0.1";
public int port = ; public GameObject localPlayer; public static MyNetworkManager Instance;
public NetworkClient unetClient; bool serverStarted = false;
bool clientCreated = false; AddPlayerMessage addPlayerMsg = new AddPlayerMessage();//每个player加入游戏时的小心容器
Dictionary<NetworkConnection, string> allClients = new Dictionary<NetworkConnection, string>();
NetworkConnection lastClient;//测试用的 #region PUBLIC ATTRIBUTES
public int numPlayers
{
get
{
int numPlayers = ;
for (int i = ; i < NetworkServer.connections.Count; i++)
{
var conn = NetworkServer.connections[i];
if (conn == null)
continue; for (int ii = ; ii < conn.playerControllers.Count; ii++)
{
if (conn.playerControllers[ii].IsValid)
{
numPlayers += ;
}
}
}
return numPlayers;
}
} public int numClients
{
get
{
return NetworkServer.connections.Count;
}
} #endregion #region CALLBACKS public Action onStartServer;
public Action onStartHost;
public Action<NetworkClient> onStartClient;
public Action onStopServer;
public Action onStopClient; public Action<NetworkMessage> onServerConncetedAction;//服务端接收到client事件
public Action<NetworkMessage> onServerDisconnectedAction;//客户端断开连接时服务端事件
public Action<NetworkMessage> onClientConncetedAction;//客户端连接到server事件
public Action<NetworkMessage> onClientDisonncetedAction;//客户端连接到server事件 #endregion #region PUBLIC METHODS public void StartServer(bool isServer = true)
{
if(!serverStarted)
{
NetworkServer.Listen(ip, port);
RegisterServerMessage(); //Debug.Log("Server started...");
LogInfo.theLogger.Log("Server started..."); if(!isServer)
{
unetClient = ClientScene.ConnectLocalServer();
RegisterClientMessage(unetClient); LogInfo.theLogger.Log("Local Client Created...");
} if(onStartServer!=null)
{
onStartServer();
}
}
} public void StartClient()
{
if (!clientCreated)
{
unetClient = new NetworkClient();
RegisterClientMessage(unetClient);
unetClient.Connect(ip, port); //Debug.Log("Client connecting...");
LogInfo.theLogger.Log("Client connecting..."); if (onStartClient != null)
{
onStartClient(unetClient);
}
}
} public void StartHost()
{
StartServer(false); if(onStartHost!=null)
{
onStartHost();
}
} public void StopServer(bool isServer = true)
{
foreach(var conn in NetworkServer.connections)
{
if(conn!=null)
NetworkServer.DestroyPlayersForConnection(conn);
} NetworkServer.Shutdown(); serverStarted = false; if (onStopServer != null)
{
onStopServer();
} if (!isServer) StopClient();
} public void StopClient()
{
unetClient.Disconnect();
unetClient.Shutdown();
unetClient = null;
ClientScene.DestroyAllClientObjects(); clientCreated = false; if(onStopClient!=null)
{
onStopClient();
}
} #endregion #region PRIVATE METHODS void RegisterServerMessage()
{
NetworkServer.RegisterHandler(MsgType.Connect, OnServerConnect);
NetworkServer.RegisterHandler(MsgType.Disconnect, OnServerDisconnect);//如果stopServer则不会触发此事件,只有客户端主动断开连接(stopclient)时触发
NetworkServer.RegisterHandler(MsgType.AddPlayer, OnServerAddPlayer);
NetworkServer.RegisterHandler(MsgType.RemovePlayer, OnServerRemovePlayer); NetworkServer.RegisterHandler(CustomerMsgType.StringMsg, OnServerReceiveStringMsg);
} void RegisterClientMessage(NetworkClient client)
{
client.RegisterHandler(MsgType.Connect, OnClientConnect);
client.RegisterHandler(MsgType.Disconnect, OnClientDisconnect);//服务端主动断开或者stopServer时触发,但客户端主动断开连接(stopClient)时不会触发
client.RegisterHandler(CustomerMsgType.StringMsg, OnClientReceiveStringMsg); if (localPlayer!=null)
{
ClientScene.RegisterPrefab(localPlayer);
}
} //server端接收到client连接触发
void OnServerConnect(NetworkMessage msg)
{
NetworkConnection conn = msg.conn;
lastClient = conn; if (onServerConncetedAction != null)
{
onServerConncetedAction(msg);
} Debug.Log("Client " + conn.connectionId + " is connected...");
LogInfo.theLogger.Log("Client " + conn.connectionId + " is connected...");
} //client断开连接时,server触发
void OnServerDisconnect(NetworkMessage msg)
{
NetworkConnection conn = msg.conn;
NetworkServer.DestroyPlayersForConnection(conn);//断开所有与conn对应的游戏物体
conn.Disconnect();
conn.Dispose(); if (onServerDisconnectedAction != null)
{
onServerDisconnectedAction(msg);
} LogInfo.theLogger.Log("Client " + conn.connectionId + " is disconnected...");
} void OnServerAddPlayer(NetworkMessage msg)
{
//var message = msg.ReadMessage<CustomerMsgType.StringMessage>();
//Debug.Log(message.stringMsg);
var player = Instantiate(localPlayer);
msg.ReadMessage(addPlayerMsg);
//Debug.Log(Encoding.Default.GetString(addPlayerMsg.msgData));
NetworkServer.AddPlayerForConnection(msg.conn, player, addPlayerMsg.playerControllerId); LogInfo.theLogger.Log("Client "+msg.conn.connectionId+" is added");
} void OnServerRemovePlayer(NetworkMessage msg)
{
LogInfo.theLogger.Log("Player removded");
} void OnServerReceiveStringMsg(NetworkMessage msg)
{
var receivedMsg = msg.ReadMessage<CustomerMsgType.StringMessage>();
//var newMsg = "Server received:" + receivedMsg.stringMsg; LogInfo.theLogger.Log(receivedMsg.stringMsg); var message = new CustomerMsgType.StringMessage();
message.stringMsg = "Server received:" + receivedMsg.stringMsg ;
NetworkServer.SendToClient(lastClient.connectionId, CustomerMsgType.StringMsg, message);
} //client连接到server时触发
void OnClientConnect(NetworkMessage msg)
{
NetworkConnection conn = msg.conn;
ClientScene.Ready(conn); CustomerMsgType.StringMessage stringMsg = new CustomerMsgType.StringMessage();
stringMsg.stringMsg = "ttt";
ClientScene.AddPlayer(conn, (short)conn.connectionId, stringMsg); if (onClientConncetedAction != null)
{
onClientConncetedAction(msg);
} Debug.Log("Client is connected to server...");
LogInfo.theLogger.Log("Client is connected to server...");
} void OnClientDisconnect(NetworkMessage msg)
{
//NetworkConnection conn = msg.conn;
StopClient(); if (onClientDisonncetedAction != null)
{
onClientDisonncetedAction(msg);
} LogInfo.theLogger.Log("Client is disconnected to server...");
} void OnClientReceiveStringMsg(NetworkMessage msg)
{
var receivedMsg = msg.ReadMessage<CustomerMsgType.StringMessage>(); LogInfo.theLogger.Log(receivedMsg.stringMsg);
} #endregion private void Start()
{
Application.runInBackground = true;
Instance = this;
}
}
消息代码:
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking; public class CustomerMsgType
{
public const short StringMsg = ;
public const short FileMsg = ; public class StringMessage : MessageBase//此类unet有定义,此处定义多此一举
{
public string stringMsg;
} public class FileMessage : MessageBase
{
public string fileType;
public byte[] fileContent;
}
}
NetworkManager网络通讯_破产版NetworkManager(五)的更多相关文章
- NetworkManager网络通讯_问题汇总(四)
此篇来填坑,有些坑是unet自身问题,而大部分则是理解不准确造成的(或者unity定义太复杂) 问题一: isLocalPlayer 值一直是false 出现场景:NetworkLobbyPlayer ...
- NetworkManager网络通讯_NetworkLobbyManager(三)
此部分可以先建立游戏大厅,然后进入游戏,此处坑甚多耗费大量时间.国内百度出来的基本没靠谱的,一些专栏作家大V也不过是基本翻译了一下用户手册(坑啊),只能通过看youtube视频以及不停的翻阅用户手册解 ...
- NetworkManager网络通讯_NetworkManager(二)
本文主要来实现一下自定UI(实现HUD的功能),并对Network Manger进行深入的讲解. 1)自定义manager 创建脚本CustomerUnetManger,并继承自NetworkMang ...
- NetworkManager网络通讯_Example(一)
---恢复内容开始--- 用户手册,范例精讲. 用户手册上给出了一个简单的范例,并指出可以以此为基础进行相开发,再次对范例进行精讲.(NetworkManager对使用unity的轻量级游戏开发有很大 ...
- NetworkManager网络通讯_networkReader/Writer(六)
unet客户端和服务端进行消息发送时可以采用上一节中方法,也可以直接用networkReader/Writer类进行发送 (一)服务端/客户端注册消息 ; m_Server.RegisterHandl ...
- Ubuntu中启用关闭Network-manager网络设置问题!
Ubuntu中启用关闭Network-manager网络设置问题! [Server版本] 在UbuntuServer版本中,因为只存有命令行模式,所以要想进行网络参数设置,只能通过修改/etc/net ...
- 容联云通讯_提供网络通话、视频通话、视频会议、云呼叫中心、IM等融合通讯能力开放平台。
容联云通讯_提供网络通话.视频通话.视频会议.云呼叫中心.IM等融合通讯能力开放平台. undefined
- 【unix网络编程第三版】阅读笔记(五):I/O复用:select和poll函数
本博文主要针对UNP一书中的第六章内容来聊聊I/O复用技术以及其在网络编程中的实现 1. I/O复用技术 I/O多路复用是指内核一旦发现进程指定的一个或者多个I/O条件准备就绪,它就通知该进程.I/O ...
- DIOCP网络通讯流程
DIOCP 运作核心探密 原文连接: http://blog.qdac.cc/?p=2362 原作者: BB 天地弦的DIOCP早已经广为人知了,有很多的同学都用上了它,甚至各种变异.修改版本也出 ...
随机推荐
- Jmeter BeanShell 执行多次问题,每发送一次请求执行一次BeanShell问题
前言:(此问题耗时半天) 提供解决思路的博主又有新问题了. 如图所示,写了一个BeanShell从文件中去获取值之后给测试计划的变量赋值. 问题来了,当禁用b的情况下,a只执行一次.当启用b请求的情况 ...
- 用 CocosCreator 快速开发推箱子游戏
游戏总共分为4个功能模块: - 开始游戏(menuLayer) - 关卡选择(levelLayer) - 游戏(gameLayer) - 游戏结算(gameOverLayer) Creator内组件效 ...
- Java入门系列之hashCode和equals(十二)
前言 前面两节内容我们详细讲解了Hashtable算法和源码分析,针对散列函数始终逃脱不掉hashCode的计算,本节我们将详细分析hashCode和equals,同时您将会看到本节内容是从<E ...
- Redis 相关功能和实用命令(五)
慢查询原因分析 由于 Redis 是单线程的,它内部维护了一个命令队列,所以当有耗时的命令出现时,比如 keys *,后面的命令会被阻塞,通查查出慢查询可以对服务进一步优化. 设置慢查询阀值:默认10 ...
- 原创电子书《菜鸟程序员成长之路:从技术小白到阿里巴巴Java工程师》
<菜鸟程序员成长之路:从技术小白到阿里巴巴Java工程师> 国庆节快乐!一年一度长度排第二的假期终于来了. 难得有十一长假,作者也想要休息几天啦. 不管你是选择出门玩,还是在公司加班,在学 ...
- Java 学习笔记之 线程isAlive方法
isAlive方法: 方法isAlive()功能是判断当前线程是否处于活动状态. 活动状态就是线程启动且尚未终止,比如正在运行或准备开始运行. public class IsAliveThread e ...
- Laravel Entrust 权限管理扩展包的使用笔记
简介 Entrust 是一个简洁而灵活的基于角色进行权限管理的 Laravel 扩展包.针对 Laravel 5,官方推荐的安装版本是 5.2.x-dev.它的详细使用方法请查看 Entrust Gi ...
- 对接第三方服务引起的小思考-回调和Sign算法
背景 最近在对接一个同事写的支付公用模块,然后对第三方服务引起一两个小思考. 思考 回调 来看看我们同事是如何做回调的. 首先,请求支付接口的时候,将回调URL作为请求body的一个参数[不加密] ...
- parse_args(argsparse):python和命令行之间的交互
初始化 假设我们创建一个“argp.py”的文件. import argparse # 引入模块 # 建立解析对象 parser = argparse.ArgumentParser() parser. ...
- 推荐一款超好用的工具cmder
今天来推荐一个超级好用的命令行工具:cmder 一款Windows环境下非常简洁美观易用的cmd替代者,它支持了大部分的Linux命令.支持ssh连接linux,使用起来非常方便.比起cmd.powe ...