public ProtoMsg ProtoToData <T>(T protoMsg) { Type type = typeof(T); IProtoItem item = protoListSender.GetItemByType(type); if (item == null) { Loger.LogTag("Proto", "ProtoToData " + protoMsg + "没找到对应的协议"); return(default(ProtoMsg)); } MemoryStream stream = new MemoryStream(); ProtoBuf.Serializer.Serialize <T>(stream, protoMsg); stream.Position = 0; ProtoMsg msg = new ProtoMsg(); msg.protoId = item.opcode; msg.bytes = stream.ToArray(); stream.Dispose(); return(msg); }
public bool Send(TcpClient client, ProtoMsg frame) #endif { if (client == null) { return(false); } //确保我们没有写入同一个客户端的竞争条件 // Make sure that we don't have any race conditions with writing to the same client lock (client) { try { //从帧中获取原始字节并发送 // Get the raw bytes from the frame and send them byte[] data = frame.GetData(); RawWrite(client, data); return(true); } catch { //客户端不再连接或无响应 // The client is no longer connected or is unresponsive } } return(false); }
/// <summary> /// The direct byte send method to the specified client /// </summary> /// <param name="client">The target client that will receive the frame</param> /// <param name="frame">The frame that is to be sent to the specified client</param> /// <summary> ///直接字节发送方法到指定的客户端 /// </ summary> /// <param name =“client”>将接收帧的目标客户端</ param> /// <param name =“frame”>要发送到指定客户端的帧</ param> public virtual void Send(ProtoMsg frame) { //确保我们没有写入同一个客户端的竞争条件 // Make sure that we don't have any race conditions with writing to the same client lock (client) { //从帧中获取原始字节并发送 // Get the raw bytes from the frame and send them byte[] data = frame.GetData(); RawWrite(data); } }
/// <summary> /// 无限循环在单独的线程上监听来自所有连接客户端的新数据。 /// readThreadCancel设置为true时,此循环会中断 /// /// Infinite loop listening for new data from all connected clients on a separate thread. /// This loop breaks when readThreadCancel is set to true /// </summary> protected ReadState Read() { if (disconnectedSelf) { return(ReadState.Disconnect); } NetworkStream stream = client.GetStream(); if (stream == null) //Some reason the stream is null! //某些原因流为空! { return(ReadState.Continue); } //如果流不再可读,则断开连接 // If the stream no longer can read then disconnect if (!stream.CanRead) { Disconnect(true); return(ReadState.Disconnect); } //如果没有可用的数据,则通过休眠线程释放CPU // If there isn't any data available, then free up the CPU by sleeping the thread if (!stream.DataAvailable) { return(ReadState.Continue); } int available = client.Available; if (available == 0) { return(ReadState.Continue); } // 读取消息 ProtoMsg protoMsg = GetNextBytes(stream, available, false); //客户端已经告诉服务器它正在断开连接 if (protoMsg.protoId == ProtoId.ConnectionClose) { Disconnect(true); return(ReadState.Disconnect); } proto.OnMessage(protoMsg, server); return(ReadState.Void); }
public void SendMessage <T>(T protoMsg, TcpClient client) { Type type = typeof(T); IProtoItem item = protoListSender.GetItemByType(type); if (item == null) { Loger.LogTag("Proto", "-> " + protoMsg + "没找到对应的协议"); return; } Loger.LogTag("Proto", "-> " + item); ProtoMsg msg = ProtoToData <T>(protoMsg); baseTcp.SendToPlayer(client, msg); }
/// <summary> /// 接收消息 /// </summary> public void OnMessage(ProtoMsg msg, NetworkingPlayer player) { IProtoItem item = protoListListener.GetItemByOpcode(msg.protoId); if (item != null) { Loger.LogTag("Proto", "<= " + item); } else { Loger.LogTag("Proto", "<= " + msg.protoId + "没找到对应的协议"); } if (item != null && item.hasListen) { item.Handle(msg.bytes, player); } }
/// <summary> /// Goes through all of the currently connected players and send them the frame /// </summary> /// <param name="frame">The frame to send to all of the connected players</param> /// <summary> ///通过所有当前连接的玩家,并将其发送给他们 /// </ summary> /// <param name =“frame”>发送给所有连接的播放器的帧</ param> public void SendAll(ProtoMsg frame, Receivers receivers = Receivers.All, NetworkingPlayer skipPlayer = null) { lock (Players) { foreach (NetworkingPlayer player in Players) { if (!commonServerLogic.PlayerIsReceiver(player, Me, receivers, skipPlayer)) { continue; } try { Send(player.TcpClientHandle, frame); } catch { Disconnect(player, true); } } } }
/// <summary> /// 读取当前的客户端流,并从中取出下一组数据 /// </summary> /// <param name =“playerClient”>要从</ param>中读取的客户端 /// <param name =“usingMask”>更改算法以查找要使用的字节中的掩码</ param> /// <returns>为这个帧读取的字节</ returns> protected ProtoMsg GetNextBytes(NetworkStream stream, int available, bool usingMask) { ProtoMsg msg = new ProtoMsg(); //将缓冲区设置为现在有可用字节的长度 byte[] bytes = new byte[9]; // 包头结构: 前四个字节表示数据包长度, 随后两字节表示消息类型 // int32 :总长度, 包含包头及包尾长度 // int16 :消息类型 stream.Read(bytes, 0, 6); int length = BitConverter.ToInt32(bytes, 0); int propId = BitConverter.ToInt16(bytes, 4); length -= 6 - 9; // 包体 byte[] body = null; if (length > 0) { body = new byte[length]; stream.Read(body, 6, length); } // 包尾 包尾结构: 1个字节表示包尾类型, 随后8个字符表示类型参数 stream.Read(bytes, 6 + length, 9); byte fromType = bytes[0]; long fromId = BitConverter.ToInt64(bytes, 1); msg.protoId = propId; msg.bytes = body; msg.fromType = fromType; msg.fromId = fromId; return(msg); }
public virtual void SendToPlayer(TcpClient client, ProtoMsg frame) { }
/// <summary> /// 无限循环在单独的线程上监听来自所有连接客户端的新数据。 /// readThreadCancel设置为true时,此循环会中断 /// /// Infinite loop listening for new data from all connected clients on a separate thread. /// This loop breaks when readThreadCancel is set to true /// </summary> private void ReadClients() { //故意无限循环 // Intentional infinite loop while (IsBound && !NetWorker.EndingSession) { try { //如果读取已被标记为取消,则从此循环中断开 // If the read has been flagged to be canceled then break from this loop if (readThreadCancel) { return; } //这将遍历所有玩家,因此请确保将锁设置为 //防止来自其他线程的任何更改 // This will loop through all of the players, so make sure to set the lock to // prevent any changes from other threads lock (Players) { for (int i = 0; i < Players.Count; i++) { //如果读取已被标记为取消,则从此循环中断开 // If the read has been flagged to be canceled then break from this loop if (readThreadCancel) { return; } NetworkStream playerStream = null; if (Players[i].IsHost) { continue; } try { lock (Players[i].MutexLock) { //尝试获取客户端流,如果它仍然可用 // Try to get the client stream if it is still available playerStream = Players[i].TcpClientHandle.GetStream(); } } catch { //无法获取客户端的流,因此强制断开连接 //Console.WriteLine("Exception异常:无法为客户端获取流(强制断开连接)“); // Failed to get the stream for the client so forcefully disconnect it //Console.WriteLine("Exception: Failed to get stream for client (Forcefully disconnecting)"); Disconnect(Players[i], true); continue; } //如果播放器不再连接,请确保正确断开连接 // If the player is no longer connected, then make sure to disconnect it properly if (!Players[i].TcpClientHandle.Connected) { Disconnect(Players[i], false); continue; } //如果有任何数据可用,则只有继续阅读此客户端 // Only continue to read for this client if there is any data available for it if (!playerStream.DataAvailable) { continue; } int available = Players[i].TcpClientHandle.Available; try { lock (Players[i].MutexLock) { // 设置消息ping时间 Players[i].Ping(); // 读取消息 ProtoMsg protoMsg = GetNextBytes(playerStream, available, false); //客户端已经告诉服务器它正在断开连接 if (protoMsg.protoId == ProtoId.ConnectionClose) { //确认连接关闭 protoServer.SendConnectionClose(Players[i].TcpClientHandle); Disconnect(Players[i], false); continue; } protoServer.OnMessage(protoMsg, Players[i]); } } catch { //播放器发送无效数据,请断开连接 Disconnect(Players[i], true); } } } //检查所有挂起的断开连接并清理它们 //完成并确定断开连接 CleanupDisconnections(); //睡眠,这样我们就可以从这个线程释放一些CPU Thread.Sleep(10); } catch (Exception ex) { BMSLog.LogException(ex); } } }
public override void SendToPlayer(TcpClient client, ProtoMsg frame) { Send(client, frame); }
/// <summary> /// The direct byte send method to the specified client /// </summary> /// <param name="client">The target client that will receive the frame</param> /// <param name="frame">The frame that is to be sent to the specified client</param> /// <summary> ///直接字节发送方法到指定的客户端 /// </ summary> /// <param name =“client”>将接收帧的目标客户端</ param> /// <param name =“frame”>要发送到指定客户端的帧</ param> #if WINDOWS_UWP public bool Send(StreamSocket client, ProtoMsg frame)