通用客户端网络模块

第一部分 框架部分

NetManager

网络事件

之前写过NetManager类,现在会丰富这个类,新加一些功能。新定义三个事件

public enum NetEvent
{
	ConnectSucc = 1,
	ConnectFail = 2,
	Close = 3,
}

每种事件触发回调函数,类似之前的写法利用委托,之前是利用Dictionary<string,MsgListener>,现在采用Dictionary<NetEvent,EventListener>
相应的逻辑处理,当之前的事件已经有了回调函数了,就采用+=,这样触发回调函数的时候,会触发多个回调函数,是委托的写法。

//添加事件监听
	public static void AddEventListener(NetEvent netEvent, EventListener listener){
		//添加事件
		if (eventListeners.ContainsKey(netEvent)){
			eventListeners[netEvent] += listener;
		}
		//新增事件
		else{
			eventListeners[netEvent] = listener;
		}
	}
	//删除事件监听
	public static void RemoveEventListener(NetEvent netEvent, EventListener listener){
		if (eventListeners.ContainsKey(netEvent)){
			eventListeners[netEvent] -= listener;
		}
	}

上面只是在NetEventEventListener之间建立连接,但是并没有执行监听函数,所以当要执行回调函数的时候调用

	//分发事件
	private static void FireEvent(NetEvent netEvent, String err){
		if(eventListeners.ContainsKey(netEvent)){
			eventListeners[netEvent](err);
		}
	}

连接服务端

具体细分了连接的状态,未连接,正在连接,已经连接。当未连接的时候isConnecting = false,正在连接的时候isConnecting = true,一个参数还不能表示三个状态,socket还自带了一个状态,当连接成功的时候socket.Connected == true,就可以成功区分三个状态。还有一个参数设置socket.NoDelay = true;,这个参数的意思是,在网络游戏中,如果有很多的简短的信息,每次单独发送,报头会占用太多空间,所以就等到一定大小再合并发送,但是一般实时性要求高的时候,不需要合并发送,所以把NoDelay设置为true

初始化操作,首先清缓存,并且涉及到心跳机制(ping -pong),下面介绍。

最后回调的时候调用FireEvent处理相应的事件。


//连接
	public static void Connect(string ip, int port)
	{
		//状态判断
		if(socket!=null && socket.Connected){
			Debug.Log("Connect fail, already connected!");
			return;
		}
		if(isConnecting){
			Debug.Log("Connect fail, isConnecting");
			return;
		}
		//初始化成员
		InitState();
		//参数设置
		socket.NoDelay = true;
		//Connect
		isConnecting = true;
		socket.BeginConnect(ip, port, ConnectCallback, socket);
	}

	//初始化状态
	private static void InitState(){
		//Socket
		socket = new Socket(AddressFamily.InterNetwork,
			SocketType.Stream, ProtocolType.Tcp);
		//接收缓冲区
		readBuff = new ByteArray();
		//写入队列
		writeQueue = new Queue<ByteArray>();
		//是否正在连接
		isConnecting = false;
		//是否正在关闭
		isClosing = false;
		//消息列表
		msgList = new List<MsgBase>();
		//消息列表长度
		msgCount = 0;
		//上一次发送PING的时间
		lastPingTime = Time.time;
		//上一次收到PONG的时间
		lastPongTime = Time.time;
		//监听PONG协议
		if(!msgListeners.ContainsKey("MsgPong")){
			AddMsgListener("MsgPong", OnMsgPong);
		}
	}

	//Connect回调
	private static void ConnectCallback(IAsyncResult ar){
		try{
			Socket socket = (Socket) ar.AsyncState;
			socket.EndConnect(ar);
			Debug.Log("Socket Connect Succ ");
			FireEvent(NetEvent.ConnectSucc,"");
			isConnecting = false;
			//开始接收
			socket.BeginReceive( readBuff.bytes, readBuff.writeIdx, 
				                            readBuff.remain, 0, ReceiveCallback, socket);

		}
		catch (SocketException ex){
			Debug.Log("Socket Connect fail " + ex.ToString());
			FireEvent(NetEvent.ConnectFail, ex.ToString());
			isConnecting = false;
		}
	} 

心跳机制

是在第五章提到过的机制,主要是服务端判断客户端还在不在的方法。因为在网络游戏中,服务端的socket资源相对来说更宝贵,所以无论客户端因为什么原因,一段时间连不上服务端就要把socket释放掉。这时候就要用心跳机制。客户端每隔固定的时间(比如30s)发送PING协议,服务端接受到PING消息之后,会发送PONG消息,服务端会用当前的时间与最后一次收到的PING消息做差,一但发现时间超过某个值就会认为客户端掉线,然后释放掉对应的socket,同时客户端这边也会判断时间,所以也会记录PONG值,用当前的时间与最后一次收到的PONG消息做差,一但发现时间超过某个值就会认为无法连接到服务端,就会断开连接。

	//发送PING协议
	private static void PingUpdate(){
		//是否启用
		if(!isUsePing){
			return;
		}
		//发送PING
		if(Time.time - lastPingTime > pingInterval){
			MsgPing msgPing = new MsgPing();
			Send(msgPing);
			lastPingTime = Time.time;
		}
		//检测PONG时间
		if(Time.time - lastPongTime > pingInterval*4){
			Close();
		}
	}

	//监听PONG协议
	private static void OnMsgPong(MsgBase msgBase){
		lastPongTime = Time.time;
	}

关闭连接

第五章提到过的,四次挥手中对数据的处理.客户端先发送FIN,服务端接收到FIN之后,会发送ACK给客户端并且会发送FIN,自己进入等待关闭状态,客户端收到ACK之后会发送ACK给服务端,自己进入等待关闭状态,服务端收到ACK之后,释放socket资源。但是有可能关闭之前,还有数据还没有发送,这时候要继续发送消息,同时延迟关闭。用isClosing表示进入关闭状态,但是并不关闭,而是在SendCallback中,发送完数据再判断isClosing的值,并选择是否关闭。

//关闭连接
	public static void Close(){
		//状态判断
		if(socket==null || !socket.Connected){
			return;
		}
		if(isConnecting){
			return;
		}
		//还有数据在发送
		if(writeQueue.Count > 0){
			isClosing = true;
		} 
		//没有数据在发送
		else{
			socket.Close();
			FireEvent(NetEvent.Close
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值