极简网络框架

//客户端

==========首先来个单例

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Singleton<T> where T:class,new()
{
private static T _instance;
private static readonly Object _lock = new Object();
public static T Instance
{
get
{
if(_instance == null)
{
lock(_lock)
{
if (_instance == null)
{
_instance = new T();
}
}
}
return _instance;
}
}

}

//==================消息中心

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MessageCenter : Singleton<MessageCenter>
{
Dictionary<int, Action<object>> dic = new Dictionary<int, Action<object>>();

public void AddListen(int id,Action<object> action)
{
if(dic.ContainsKey(id))
{
dic[id] += action;
}
else
{
dic.Add(id, action);
}
}

public void RemoveListen(int id,Action<object> action)
{
if(dic.ContainsKey(id))
{
dic[id] -= action;
if(dic[id] == null)
{
dic.Remove(id);
}
}
}

public void BroadCast(int id , params object[] objs)
{
if(dic.ContainsKey(id))
{
dic[id](objs);
}
}
}

//=============unity 中的启动项

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameManager : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
Client_NetManager.Instance.Init();
}

// Update is called once per frame
void Update()
{
Client_NetManager.Instance.UpData();
}
private void OnApplicationQuit()
{
Client_NetManager.Instance.Close();
}
}

//============客户端框架

using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Net;
using System.Linq;
using UnityEngine;
using System;

public class Client_NetManager : Singleton<Client_NetManager>
{
private Socket socket;
public Queue<byte[]> que = new Queue<byte[]>();
public byte[] data = new byte[1024];
public byte[] stream = new byte[0];
public void Init()
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.BeginConnect("127.0.0.1", 12345, OnConnect, null);
}

private void OnConnect(IAsyncResult ar)
{
socket.EndConnect(ar);
socket.BeginReceive(data, 0, data.Length, SocketFlags.None, OnReceive, null);
IPEndPoint ip = socket.LocalEndPoint as IPEndPoint;
MID.MyIp = ip.Address + ":" + ip.Port;
}

private void OnReceive(IAsyncResult ar)
{
try
{
int len = socket.EndReceive(ar);
if (len > 0)//有数据
{
byte[] data0 = new byte[len];
Buffer.BlockCopy(data, 0, data0, 0, len);
stream = stream.Concat(data0).ToArray();
while (stream.Length >= 2)
{
ushort oneLen = BitConverter.ToUInt16(stream, 0);
int allLen = oneLen + 2;
if (stream.Length >= allLen)
{
byte[] oneData = new byte[oneLen];
Buffer.BlockCopy(stream, 2, oneData, 0, oneLen);

que.Enqueue(oneData);

int syLen = stream.Length - allLen;
if (syLen > 0)
{
byte[] syData = new byte[syLen];
Buffer.BlockCopy(stream, allLen, syData, 0, syLen);
stream = syData;
}
else
{
stream = new byte[0];
break;
}
}
else
{
break;
}
}
socket.BeginReceive(data, 0, data.Length, SocketFlags.None, OnReceive, null);
}
}
catch (Exception e)
{
Debug.Log(e);
}
}
public void UpData()
{
while (que.Count>0)
{
byte[] oneData = que.Dequeue();
int id = BitConverter.ToInt32(oneData, 0);

byte[] body = new byte[oneData.Length - 4];
Buffer.BlockCopy(oneData, 4, body, 0, body.Length);

MessageCenter.Instance.BroadCast(id, body);
}
}
public void Send(int id, byte[] body)
{
byte[] head = BitConverter.GetBytes(id);
byte[] len = BitConverter.GetBytes((ushort)(head.Length + body.Length));
byte[] data = new byte[0];
data = data.Concat(len).ToArray();
data = data.Concat(head).ToArray();
data = data.Concat(body).ToArray();
socket.BeginSend(data, 0, data.Length, SocketFlags.None, OnSend, null);
}

private void OnSend(IAsyncResult ar)
{
int len = socket.EndSend(ar);
Console.WriteLine("发送长度====》" + len);
}
public void Close()
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
}

//=========一个消息号的类 静态或者是常量类,为了不让发送消息乱(下面是个例子)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MID : MonoBehaviour
{
public static string MyIp = null;

//登录
public const int S_C_LOGIN = 1001;
public const int C_S_LOGIN = 1002;
//玩家上线
public const int S_C_MYONLINE = 1003;
public const int S_C_OTHERONLINE = 1004;
//初始创建物品
public const int S_C_CREATGOODS = 1005;
//删除物品 ,生成物品
public const int S_C_SYNGOOD = 1006;
public const int C_S_SYNGOOD = 1007;
//移动
public const int S_C_MOVE = 1008;
public const int C_S_MOVE = 1009;
//离线
public const int OUTLINE = 1010;
//创建篝火
public const int C_S_CREATGH = 1011;
public const int S_C_CREATGH = 1012;
//进食
public const int S_C_EATMEET = 1013;
public const int C_S_EATMEET = 1014;
//掉血
public const int S_C_DIAOXUE = 1005;
public const int C_S_DIAOXUE = 1006;
}

//==============================服务器内容

//同样的消息中心    /   单例      / 消息号类   来一套

//服务器的启动项

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Six_MonthExam_Sever
{
public class Program
{
static void Main(string[] args)
{
Sever_NetManager.Instance.Init();
Console.ReadKey();
}
}
}

//   ===========服务器的框架

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Six_MonthExam_Sever
{
public class Sever_NetManager:Singleton<Sever_NetManager>
{
private Socket socket;
public List<Client> clients = new List<Client>();

public void Init()
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Any, 12345));
socket.Listen(5);
Console.WriteLine("服务器启动");
socket.BeginAccept(OnAccept, null);
}

private void OnAccept(IAsyncResult ar)
{
Client client = new Client();
client.socket = socket.EndAccept(ar);
IPEndPoint ip = client.socket.RemoteEndPoint as IPEndPoint;
client.ip = ip.Address + ":" + ip.Port;
clients.Add(client);
Console.WriteLine("客户端"+client.ip+"已连接");
client.socket.BeginReceive(client.data, 0, client.data.Length, SocketFlags.None, OnReceive, client);
socket.BeginAccept(OnAccept, null);
}

private void OnReceive(IAsyncResult ar)
{
try
{
Client client = ar.AsyncState as Client;
int len = client.socket.EndReceive(ar);
if(len>0)
{
byte[] data0 = new byte[len];
Buffer.BlockCopy(client.data, 0, data0, 0, len);
client.stream = client.stream.Concat(data0).ToArray();
while (client.stream.Length>=2)
{
ushort oneLen = BitConverter.ToUInt16(client.stream, 0);
int allLen = oneLen + 2;
if(client.stream.Length>=allLen)
{
byte[] oneData = new byte[oneLen];
Buffer.BlockCopy(client.stream, 2, oneData, 0, oneData.Length);

int id = BitConverter.ToInt32(oneData, 0);
byte[] body = new byte[oneData.Length - 4];
Buffer.BlockCopy(oneData, 4, body, 0, oneData.Length - 4);

MessageManager.Instance.BroadCast(id, body, client);
int syLen = client.stream.Length - allLen;
if(syLen>0)
{
byte[] syData = new byte[syLen];
Buffer.BlockCopy(client.stream, allLen, syData, 0, syLen);
client.stream = syData;
}
else
{
client.stream = new byte[0];
break;
}
}
else
{
break;
}
}
client.socket.BeginReceive(client.data, 0, client.data.Length, SocketFlags.None, OnReceive, client);
}
else
{
client.socket.Shutdown(SocketShutdown.Both);
Console.WriteLine(client.ip+"离线");
clients.Remove(client);
client.socket.Close();
}
}
catch (Exception e)
{

Console.WriteLine(e);
}
}

public void Send(int id,byte[] body,Client client)
{
byte[] head = BitConverter.GetBytes(id);
byte[] len = BitConverter.GetBytes((ushort)(head.Length + body.Length));
byte[] data = new byte[0];
data = data.Concat(len).ToArray();
data = data.Concat(head).ToArray();
data = data.Concat(body).ToArray();
client.socket.BeginSend(data, 0, data.Length, SocketFlags.None, OnSend, client);
}

private void OnSend(IAsyncResult ar)
{
Client client = ar.AsyncState as Client;
int len = client.socket.EndReceive(ar);
Console.WriteLine("发送长度:"+len);
}

public void SendAll(int id,byte[] body)
{
foreach (var item in clients)
{
Send(id, body, item);
}
}
}
}

//================谷歌旗下的Protobuf(示例)

package xxx;
syntax = "proto3";
message helloworld 
{ 
   string zzz= 123;  
   string yyy= 0;
}
//================Protobuf解和填
//发送

C_S_Login c = new C_S_Login();
c.MyName = user.text;
//发送消息给客户端
Client_NetManager.Ins.Send(MID.C_S_LOGIN,c.ToByteArray());

//接收 

object[] arr = obj as object[];
byte[] body = arr[0] as byte[];
S_C_Login s = S_C_Login.Parser.ParseFrom(body);

//记得引用命名空间

using zzz;//pb包名
using Google.Protobuf;//谷歌

 
posted @ 2023-03-27 19:52  old_Host  阅读(38)  评论(0)    收藏  举报