效果:两个客户端,一个称为客户端A,一个称为客户端B。
一个服务器。
一组协议。
客户端A发送,服务器接受到,并且转发给所有客户端。
客户端A和客户端B接收到服务器的消息转发,并且读取出来,显示到客户端A和客户端B。
1.网络层定义好DTO以及协议。
2. 客户端的chatcontroller可以去拿服务端的DTO以及调api发送DTO给服务端。
4.在客户端和服务端的controllermanager里面都要注册刚才的请求。
客户端:
服务端:
代码:
客户端:
IBaseController.cs:
using Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public interface IBaseController
{
void GetData(RequestType type, object data);
}
ChatController.cs
using System.Collections;
using System.Collections.Generic;
using Common;
using UnityEngine;
public class ChatController : IBaseController
{
public static ChatController instance = new ChatController();
public void GetData(RequestType type, object data)
{
if (type == RequestType.Chat)
{
var dto = (data as ChatDTO);
Debug.LogError("["+dto.userID+"]:"+dto.chatMsg);
}
}
public void chat(string text)
{
var dto = new ChatDTO();
dto.chatMsg = text;
dto.userID = GameModel.instance.UserID;
ClientManager.instance.SendRequest(RequestType.Chat, dto);
}
}
ChatView.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ChatView : MonoBehaviour {
void Start () {
}
void Update () {
}
public void chat()
{
ChatController.instance.chat(transform.Find("InputField").GetComponent().text);
}
}
ClientManager.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System;
using Common;
///
/// 管理服务器端的Socket
///
public class ClientManager : MonoBehaviour
{
public static ClientManager instance;
private const string IP = "127.0.0.1";
private const int PORT = 6688;
private Socket socket;
private Message msg = new Message();
private Dictionary
Message.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Common;
using System.Text;
using System.Linq;
public class Message {
private byte[] data = new byte[1024];
private int startIndex = 0;//我们存取了多少个字节的数据在数组里面
//public void AddCount(int count)
//{
// startIndex += count;
//}
public byte[] Data
{
get { return data; }
}
public int StartIndex
{
get { return startIndex; }
}
public int RemainSize
{
get { return data.Length - startIndex; }
}
///
/// 解析数据
///
public void RecieveData(int newDataAmount, Action processDataCallback)
{
startIndex += newDataAmount;
while (true)
{
if (startIndex <= 4) return;
int count = BitConverter.ToInt32(data, 0);
//接收指定长度数据
if ((startIndex - 4) >= count)
{
//获取协议码
RequestType actionCode = (RequestType)BitConverter.ToInt32(data, 4);
//找到对应request
processDataCallback(actionCode, SerializeHelper.DeserializeWithBinary(data.Skip(8).ToArray()));
Array.Copy(data, count + 4, data, 0, startIndex - 4 - count);
startIndex -= (count + 4);
}
else
{
break;
}
}
}
///
/// 打包数据
///
///
///
///
public static byte[] WriteData(RequestType actionCode, object dto)
{
//获取协议码
byte[] actionCodeBytes = BitConverter.GetBytes((int)actionCode);
//转换成二进制
byte[] dataBytes = SerializeHelper.SerializeToBinary(dto);
int dataAmount = dataBytes.Length + actionCodeBytes.Length;
//封包(头+协议码+内容)
byte[] dataAmountBytes = BitConverter.GetBytes(dataAmount);
//byte[] newBytes = dataAmountBytes.Concat(requestCodeBytes).ToArray();//Concat(dataBytes);
//return newBytes.Concat(dataBytes).ToArray();
return dataAmountBytes.Concat(actionCodeBytes).ToArray()
.Concat(dataBytes).ToArray();
}
}
ControllerManager.cs:
using Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class ControllerManager
{
public static ControllerManager instance = new ControllerManager();
public Dictionary ControllerDic = new Dictionary();
public void HandleController(RequestType type, object data)
{
ControllerDic[type].GetData( type, data );
}
private ControllerManager()
{
ControllerDic.Add(RequestType.None,new GameController());
ControllerDic.Add(RequestType.Login,new LoginController());
ControllerDic.Add(RequestType.Chat,ChatController.instance);
}
}
GameController.cs:
using Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
public class GameController : IBaseController
{
public void GetData(RequestType type, object dto)
{
if (type == RequestType.None)
{
Debug.LogError("收到服务器消息:"+ (dto as BaseDTO).data);
}
}
}
GameModel.cs:
using Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class GameModel
{
public static GameModel instance = new GameModel();
public int UserID;
public void Init()
{
ClientManager.instance.SendRequest(Common.RequestType.Login,new Common.LoginDTO());
}
}
SerializeHelper.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Xml.Serialization;
public static class SerializeHelper
{
///
/// 使用UTF8编码将byte数组转成字符串
///
///
///
public static string ConvertToString(byte[] data)
{
return Encoding.UTF8.GetString(data, 0, data.Length);
}
///
/// 使用指定字符编码将byte数组转成字符串
///
///
///
///
public static string ConvertToString(byte[] data, Encoding encoding)
{
return encoding.GetString(data, 0, data.Length);
}
///
/// 使用UTF8编码将字符串转成byte数组
///
///
///
public static byte[] ConvertToByte(string str)
{
return Encoding.UTF8.GetBytes(str);
}
///
/// 使用指定字符编码将字符串转成byte数组
///
///
///
///
public static byte[] ConvertToByte(string str, Encoding encoding)
{
return encoding.GetBytes(str);
}
///
/// 将对象序列化为二进制数据
///
///
///
public static byte[] SerializeToBinary(object obj)
{
MemoryStream stream = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(stream, obj);
byte[] data = stream.ToArray();
stream.Close();
return data;
}
///
/// 将对象序列化为XML数据
///
///
///
public static byte[] SerializeToXml(object obj)
{
MemoryStream stream = new MemoryStream();
XmlSerializer xs = new XmlSerializer(obj.GetType());
xs.Serialize(stream, obj);
byte[] data = stream.ToArray();
stream.Close();
return data;
}
///
/// 将二进制数据反序列化
///
///
///
public static object DeserializeWithBinary(byte[] data)
{
MemoryStream stream = new MemoryStream();
stream.Write(data, 0, data.Length);
stream.Position = 0;
BinaryFormatter bf = new BinaryFormatter();
object obj = bf.Deserialize(stream);
stream.Close();
return obj;
}
///
/// 将二进制数据反序列化为指定类型对象
///
///
///
///
public static T DeserializeWithBinary(byte[] data)
{
return (T)DeserializeWithBinary(data);
}
///
/// 将XML数据反序列化为指定类型对象
///
///
///
///
public static T DeserializeWithXml(byte[] data)
{
MemoryStream stream = new MemoryStream();
stream.Write(data, 0, data.Length);
stream.Position = 0;
XmlSerializer xs = new XmlSerializer(typeof(T));
object obj = xs.Deserialize(stream);
stream.Close();
return (T)obj;
}
}
=========================================================================
服务器:
ChatDTO.cs:
using System;
using System.Collections.Generic;
using System.Text;
namespace Common
{
[Serializable]
public class ChatDTO
{
public int userID;
public string chatMsg;
}
}
DTO.cs:
using System;
using System.Collections.Generic;
using System.Text;
namespace Common
{
[Serializable]
public class BaseDTO
{
public string data;
}
}
ServerType.cs:
using System;
using System.Collections.Generic;
using System.Text;
namespace Common
{
//协议类型
public enum RequestType
{
None,
Login,
Chat,
}
}
SerializeHelper.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Xml.Serialization;
public static class SerializeHelper
{
///
/// 使用UTF8编码将byte数组转成字符串
///
///
///
public static string ConvertToString(byte[] data)
{
return Encoding.UTF8.GetString(data, 0, data.Length);
}
///
/// 使用指定字符编码将byte数组转成字符串
///
///
///
///
public static string ConvertToString(byte[] data, Encoding encoding)
{
return encoding.GetString(data, 0, data.Length);
}
///
/// 使用UTF8编码将字符串转成byte数组
///
///
///
public static byte[] ConvertToByte(string str)
{
return Encoding.UTF8.GetBytes(str);
}
///
/// 使用指定字符编码将字符串转成byte数组
///
///
///
///
public static byte[] ConvertToByte(string str, Encoding encoding)
{
return encoding.GetBytes(str);
}
///
/// 将对象序列化为二进制数据
///
///
///
public static byte[] SerializeToBinary(object obj)
{
MemoryStream stream = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(stream, obj);
byte[] data = stream.ToArray();
stream.Close();
return data;
}
///
/// 将对象序列化为XML数据
///
///
///
public static byte[] SerializeToXml(object obj)
{
MemoryStream stream = new MemoryStream();
XmlSerializer xs = new XmlSerializer(obj.GetType());
xs.Serialize(stream, obj);
byte[] data = stream.ToArray();
stream.Close();
return data;
}
///
/// 将二进制数据反序列化
///
///
///
public static object DeserializeWithBinary(byte[] data)
{
MemoryStream stream = new MemoryStream();
stream.Write(data, 0, data.Length);
stream.Position = 0;
BinaryFormatter bf = new BinaryFormatter();
object obj = bf.Deserialize(stream);
stream.Close();
return obj;
}
///
/// 将二进制数据反序列化为指定类型对象
///
///
///
///
public static T DeserializeWithBinary(byte[] data)
{
return (T)DeserializeWithBinary(data);
}
///
/// 将XML数据反序列化为指定类型对象
///
///
///
///
public static T DeserializeWithXml(byte[] data)
{
MemoryStream stream = new MemoryStream();
stream.Write(data, 0, data.Length);
stream.Position = 0;
XmlSerializer xs = new XmlSerializer(typeof(T));
object obj = xs.Deserialize(stream);
stream.Close();
return (T)obj;
}
}
ChatController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Common;
using GameServer.Servers;
namespace GameServer.Server.Contrller
{
public class ChatController : IBaseController
{
public void GetData(RequestType type, object data, Client client)
{
//传入数据
var dto = data as ChatDTO;
//转发数据
client.SendDataToAll(type,dto);
}
}
}
ControllerManager.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Common;
using GameServer.Server.Contrller;
using GameServer.Servers;
namespace GameServer.Servers
{
class ControllerManager
{
public static ControllerManager instance = new ControllerManager();
public Dictionary ControllerDic = new Dictionary();
public void HandleController(RequestType type, object data, Client client)
{
ControllerDic[type].GetData( type, data, client);
}
private ControllerManager()
{
Console.WriteLine("开始注册crl");
ControllerDic.Add(RequestType.None, new GameController());
ControllerDic.Add(RequestType.Login, new LoginController());
ControllerDic.Add(RequestType.Chat, new ChatController());
}
}
}
GameController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Common;
using GameServer.Servers;
namespace GameServer.Server.Contrller
{
class GameController : IBaseController
{
public void GetData(RequestType type, object data, Client client)
{
Console.WriteLine("ww");
if (type == RequestType.None)
{
var dto = data as BaseDTO;
client.SendMessage("服务端收到消息:"+ dto.data);
}
}
}
}
IBaseController.cs:
using Common;
using GameServer.Servers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameServer.Server.Contrller
{
interface IBaseController
{
void GetData( RequestType type, object data, Client client);
}
}
Client.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using Common;
using MySql.Data.MySqlClient;
namespace GameServer.Servers
{
public class Client
{
public int ID;
private Socket socket;
private Server server;
private Message msg = new Message();
//初始化客户端
public Client(Socket socket,Server server)
{
this.socket = socket;
this.server = server;
}
//开始接收消息
public void BeginReceive()
{
if (socket == null || socket.Connected == false) return;
socket.BeginReceive(msg.Data, msg.StartIndex, msg.RemainSize, SocketFlags.None, ReceiveDataCallback, null);
SendMessage("已连接");
}
//收到消息
private void ReceiveDataCallback(IAsyncResult ar)
{
try
{
if (socket == null || socket.Connected == false) return;
int count = socket.EndReceive(ar);
if (count == 0)
{
Close();
}
msg.RecieveData(count,HandleController);
BeginReceive();
}
catch (Exception e)
{
Console.WriteLine(e);
Close();
}
}
//找到对应的Contrller
private void HandleController( RequestType type,object data)
{
ControllerManager.instance.HandleController(type, data, this);
}
//关闭
private void Close()
{
if (socket != null)
socket.Close();
server.RemoveClient(this);
}
//发送数据
public void SendData(RequestType type, object data)
{
try
{
byte[] bytes = Message.WriteData(type, data);
socket.Send(bytes);
}
catch (Exception e)
{
Console.WriteLine("无法发送消息:" + e);
}
}
//给所有客户端发送数据
public void SendDataToAll(RequestType type, object data)
{
try
{
byte[] bytes = Message.WriteData(type, data);
foreach (var item in server.clientDic)
{
item.Value.SendData(type, data);
}
}
catch (Exception e)
{
Console.WriteLine("无法发送消息:" + e);
}
}
//直接发送字符串
public void SendMessage(string msg)
{
var dto = new BaseDTO();
dto.data = msg;
SendData(RequestType.None, dto);
}
}
}
Message.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Common;
namespace GameServer.Servers
{
class Message
{
private byte[] data = new byte[1024];
private int startIndex = 0;//我们存取了多少个字节的数据在数组里面
public byte[] Data
{
get { return data; }
}
public int StartIndex
{
get { return startIndex; }
}
public int RemainSize
{
get { return data.Length - startIndex; }
}
///
/// 解析数据,解包
///
public void RecieveData(int amout, Action processDataCallback )
{
startIndex += amout;
while (true)
{
if (startIndex <= 4) return;
int count = BitConverter.ToInt32(data, 0);
if ((startIndex - 4) >= count)
{
RequestType actionCode = (RequestType)BitConverter.ToInt32(data, 4);
//string s = Encoding.UTF8.GetString(data, 12, count-8);
Console.WriteLine(actionCode);
processDataCallback(actionCode, SerializeHelper.DeserializeWithBinary(data.Skip(8).ToArray()));
Array.Copy(data, count + 4, data, 0, startIndex - 4 - count);
startIndex -= (count + 4);
}
else
{
break;
}
}
}
///
/// 打包
///
///
///
///
public static byte[] WriteData(RequestType type,object dto)
{
byte[] typeBytes = BitConverter.GetBytes((int)type);
byte[] dataBytes =SerializeHelper.SerializeToBinary(dto);
int dataLength = typeBytes.Length + dataBytes.Length;
byte[] LengthBytes = BitConverter.GetBytes(dataLength);
byte[] b =LengthBytes.Concat(typeBytes).ToArray();
return b.Concat(dataBytes).ToArray();
}
}
}
Server.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using Common;
namespace GameServer.Servers
{
public class Server
{
private Socket serverSocket;
public Dictionary clientDic = new Dictionary();
public Server() {}
//设置IP和端口,开始侦听客户端
internal void Start(string ipStr, int port)
{
var ipEndPoint = new IPEndPoint(IPAddress.Parse(ipStr), port);
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(ipEndPoint);
serverSocket.Listen(0);
serverSocket.BeginAccept(AcceptClient, null);
Console.WriteLine("开始侦听客户端");
}
//捕获客户端
private void AcceptClient(IAsyncResult ar )
{
Socket clientSocket = serverSocket.EndAccept(ar);
Client client = new Client(clientSocket,this);
client.ID = new Random().Next(0,999999999);
client.BeginReceive();
clientDic.Add(client.ID,client);
serverSocket.BeginAccept(AcceptClient, null);
Console.WriteLine("有客户端进来啦,分配ID:"+client.ID);
}
//移除客户端
public void RemoveClient(Client client)
{
RemoveClient(client.ID);
}
//移除客户端
public void RemoveClient(int clientID)
{
lock (clientDic)
{
clientDic.Remove(clientID);
}
Console.WriteLine("有客户端退出啦,分配ID:" + clientID);
}
}
}
Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GameServer.Servers;
namespace 游戏服务器端
{
class Program
{
static void Main(string[] args)
{
// var i = ControllerManager.instance;
Server server = new Server();
server.Start("127.0.0.1", 6688);
Console.ReadKey();
}
}
}