目录
一、客户端代码



连接本地服务器127.0.0.1:2012端口(如何创本地服务器,放最后说),连接成功后会回调


协议号Connect是101,其他如下,将这个Connect协议号和数据(空的字节流)放入一个mEvents队列,等待Update执行(目的应该是回到主线程才执行回调,避免一些问题)


这里Update方法就是Monobehaviour的生命周期Update,它简单地遍历队列逐个出队派发事件"DISPATCH_MESSAGE"去到如下

再回到调用lua的Network.OnSocket方法并且将 buffer.Key(协议号 101) 和 buffer.Value(空) 数据传递。

Network.OnSocket继续派发协议号作为事件名,执行OnConnect方法,至此完成一整套连接流程

其他相关的事件可以查如下找到相关的代码

由于我们lua侧仅写了1个消息协议号'104' 所以本地服务器代码也是要用104作为协议号传递,不然接收消息检测不到是104就无法正常通过消息派发并执行到对应的lua消息回调代码。

接收消息回调

TestProtoType有很多种传递消息的方式,项目默认使用ProtocalType.BINARY





好绕,最终是到了上面的WriteMessage方法,发送是以"消息长度"+"消息内容"为一条字节流传递到服务器,执行完后回调OnWrite方法

二、本地服务器代码

cs
using System;
using System.Net;
using System.Net.Sockets;
namespace SimpleNet
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
//Socket tcp
Socket listenfd = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
//bind
IPAddress ipAdr = IPAddress.Parse("127.0.0.1");
IPEndPoint ipEp = new IPEndPoint(ipAdr, 2012);
listenfd.Bind(ipEp);
//listen
listenfd.Listen(0);
Console.WriteLine("启动服务器成功");
while (true)
{
//Accept
Socket connfd = listenfd.Accept();
Console.WriteLine("服务器Accept");
//Recv 测试
byte[] readBuff = new byte[100];
int count = connfd.Receive(readBuff);
//steam
string showStr = "";
for(int i = 0; i< count; i++)
{
int b = (int)readBuff[i];
showStr += b.ToString() + " ";
}
Console.WriteLine("字节流:" + showStr);
//解析
Int16 msgLen = BitConverter.ToInt16(readBuff, 0);
Int16 protocal = BitConverter.ToInt16(readBuff, 2);
Int16 strLen = BitConverter.ToInt16(readBuff, 5);//具体还要看字节流输出来读取第几个字节是长度,若读错了下一行会报错
string str = System.Text.Encoding.UTF8.GetString(readBuff, 6, strLen);
Console.WriteLine("消息长度:" + msgLen);
Console.WriteLine("协议号:" + protocal);
Console.WriteLine("字符串:" + str);
//send 原样返回
byte[] writeBuff = new byte[count];
Array.Copy(readBuff, writeBuff, count);
connfd.Send(writeBuff);
}
}
}
}


客户端接收到服务器消息的打印,服务器是直接将客户端的消息拷贝了一份再发送给客户端。
跑代码时发现有些lua报错:FindChild相关不存在
--初始化面板--
function MessagePanel.InitPanel()
--this.btnClose = transform:FindChild("Button").gameObject; --bug代码 FindChild是不存在的接口...
this.btnClose = transform:Find("Button").gameObject;
end
三、解决服务器无法多次接收客户端消息问题
测试发现上面的服务器代码不支持多次发送和接收消息,可以修改为如下服务器代码解决:
cs
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace SimpleNet
{
class Program
{
static async Task Main(string[] args)
{
SimpleTcpServer server = new SimpleTcpServer("127.0.0.1", 2012);
await server.StartAsync();
}
}
}
cs
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace SimpleNet
{
public class SimpleTcpServer
{
private TcpListener _listener;
private string _ip;
private int _port;
public SimpleTcpServer(string ip, int port)
{
_ip = ip;
_port = port;
}
public async Task StartAsync()
{
_listener = new TcpListener(IPAddress.Parse(_ip), _port);
_listener.Start();
Console.WriteLine($"Server started on port {_port}.");
while (true)
{
TcpClient client = await _listener.AcceptTcpClientAsync();
_ = HandleClientAsync(client);
}
}
private async Task HandleClientAsync(TcpClient client)
{
NetworkStream stream = client.GetStream();
byte[] readBuff = new byte[1024];
while (true)
{
try
{
int count = await stream.ReadAsync(readBuff, 0, readBuff.Length);
if (count == 0) // Client disconnected
{
break;
}
//steam
string showStr = "";
for (int i = 0; i < count; i++)
{
int b = (int)readBuff[i];
showStr += b.ToString() + " ";
}
Console.WriteLine("字节流:" + showStr);
//解析
Int16 msgLen = BitConverter.ToInt16(readBuff, 0);
Int16 protocal = BitConverter.ToInt16(readBuff, 2);
Int16 strLen = BitConverter.ToInt16(readBuff, 5);
string str = System.Text.Encoding.UTF8.GetString(readBuff, 7, strLen);
Console.WriteLine("消息长度:" + msgLen);
Console.WriteLine("协议号:" + protocal);
Console.WriteLine("字符串:" + str);
//send 原样返回
byte[] writeBuff = new byte[count];
Array.Copy(readBuff, writeBuff, count);
await stream.WriteAsync(writeBuff, 0, writeBuff.Length);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
break;
}
}
client.Close();
}
public void Stop()
{
_listener.Stop();
}
}
}