可通过左侧目录快速找到指定框架内容 

服务端

网络管理类

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Net.Sockets;

using System.Text;

using System.Threading.Tasks;

namespace vs_Day03_practice

{

class NetMgr : Singleton

{

//其他线程要使用所以要全局

Socket socket;

public void Init()

{

//得有手机(使用ipv4查找地址,使用字节流传输数据,使用Tcp协议传输)

socket=new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

//创建手机卡(默认IP地址,自定义端口号)

IPEndPoint ip=new IPEndPoint(IPAddress.Any, 9999);

//绑定手机号

socket.Bind(ip);

//设定接听上线

socket.Listen(10);

//等待别人打电话(会阻塞线程)

//子线程被输入阻塞的时候,主线程能继续正常运行

ThreadPool.QueueUserWorkItem(Accept);

}

private void Accept(object? state) //等待别人连接(会阻塞线程)

{

Socket client=socket.Accept();

//来电显示

//获取ip地址和端口号

IPEndPoint clientIP=client.RemoteEndPoint as IPEndPoint;

Console.WriteLine("连接成功"+clientIP.Port);

//开线程收消息

ThreadPool.QueueUserWorkItem(Receive, client);

//等待下一个连接

ThreadPool.QueueUserWorkItem(Accept);

}

private void Receive(object? state)

{

Socket client = state as Socket;

//创建一个字节流用来接收消息

byte[] buffer=new byte[1024];

//接收客户端发来的消息(会阻塞线程)

int len=client.Receive(buffer,SocketFlags.None);

//收到长度为0的消息时断开连接

if (len <= 0)

{

//禁止收发消息

client.Shutdown(SocketShutdown.Both);

//关闭连接释放资源

client.Close();

return;

}

//1024是流的长度 len是消息实际长度

//截取数组前n位

byte[] data=buffer.Take(len).ToArray();

//收到消息后把消息通过消息中心分发

int id=BitConverter.ToInt32(data,0);

byte[] body = data.Skip(4).ToArray();

MessageCenter.Ins.Broadcast(id, body,client);

//开线程收消息

ThreadPool.QueueUserWorkItem(Receive, client);

}

public void Send(Socket client,int id, byte[] body) //发消息给客户端

{

//消息头 存储消息id

byte[] head=BitConverter.GetBytes(id);

//完整消息=消息头+消息内容

byte[] data=head.Concat(body).ToArray();

client.Send(data);

}

}

}

单例

internal class Singleton where T : class,new()

{

private static T ins;

public static T Ins

{

get

{

if(ins == null)

{

ins = new T();

}

return ins;

}

}

}

消息中心

internal class MessageCenter:Singleton

{

Dictionary> dic=new Dictionary>();

public void AddListen(int id, Action action)

{

if (dic.ContainsKey(id))

{

dic[id] += action;

}

else

{

dic.Add(id, action);

}

}

public void Broadcast(int id,params object[] obj)

{

if(dic.ContainsKey(id))

{

dic[id](obj);

}

}

}

主函数 

internal class Program

{

static void Main(string[] args)

{

NetMgr.Ins.Init();

while (true) { }

}

}

客户端

注意:客户端也要拥有 单例 、消息中心 直接复制服务端的拿来用就可以了

网络管理类

using System;

using System.Collections;

using System.Collections.Generic;

using System.Linq;

using System.Net.Sockets;

using System.Threading;

using UnityEditor;

using UnityEngine;

public class NetMgr : Singleton

{

Socket socket;

Queue que=new Queue();

public void Init()

{

socket=new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

socket.Connect("127.0.0.1",9999); //这里可以根据自己来输入 端口号必须与服务端一致

//收消息

ThreadPool.QueueUserWorkItem(Receive);

}

private void Receive(object state)

{

byte[] buffer=new byte[1024];

int len=socket.Receive(buffer,SocketFlags.None);

if (len <= 0)

{

socket.Shutdown(SocketShutdown.Both);

socket.Close();

return;

}

byte[] data=buffer.Take(len).ToArray();

//unity封住了多线程的调用,所以存入队列在主线程调用

que.Enqueue(data);

ThreadPool.QueueUserWorkItem(Receive);

}

// Update is called once per frame

public void Update()

{

//在主线程中取出队列的消息

while (que.Count > 0)

{

byte[] data=que.Dequeue();

int id=BitConverter.ToInt32(data,0);

byte[] body=data.Skip(4).ToArray();

MessageCenter.Ins.Broadcast(id, body);

}

}

public void Send(int id, byte[] body)

{

byte[] head=BitConverter.GetBytes(id);

byte[] data=head.Concat(body).ToArray();

socket.Send(data);

}

public void Close()//客户端主动断开

{

socket.Shutdown(SocketShutdown.Both);

socket.Close();

}

}

GameManager 

在unity上 挂载到一个空对象上就可以

public class GameManager : MonoBehaviour

{

// Start is called before the first frame update

void Start()

{

NetManager.Ins.Init();

}

// Update is called once per frame

void Update()

{

NetManager.Ins.Update();

}

private void OnApplicationQuit()

{

NetManager.Ins.Close();

}

}

参考阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。

发表评论

取消
扫码支持 支付码
返回顶部暗黑模式