Unity【Multiplayer 多人在线】- Socket 通用客户端网络模块(三)、发送数据和关闭连接

2022-08-29 17:00:07 浏览数 (1)

介绍

在阅读了罗培羽著作的Unity3D网络游戏实战一书后,博主综合自己的开发经验与考虑进行部分修改和调整,将通用的客户端网络模块和通用的服务端框架进行提取,形成专栏,介绍Socket网络编程,希望对其他人有所帮助。目录如下,链接为对应的CSDN博客地址:

一、通用服务端框架

(一)、定义套接字和多路复用

https://blog.csdn.net/qq_42139931/article/details/124051945?spm=1001.2014.3001.5501

(二)、客户端信息类和通用缓冲区结构

https://blog.csdn.net/qq_42139931/article/details/124053571?spm=1001.2014.3001.5502

(三)、Protobuf 通信协议

https://blog.csdn.net/qq_42139931/article/details/124054972?spm=1001.2014.3001.5501

(四)、数据处理和关闭连接

https://blog.csdn.net/qq_42139931/article/details/124055227?spm=1001.2014.3001.5501

(五)、Messenger 事件发布、订阅系统

https://blog.csdn.net/qq_42139931/article/details/124055392?spm=1001.2014.3001.5501

(六)、单点发送和广播数据

https://blog.csdn.net/qq_42139931/article/details/124055482?spm=1001.2014.3001.5501

(七)、时间戳和心跳机制

https://blog.csdn.net/qq_42139931/article/details/124055856?spm=1001.2014.3001.5501

二、通用客户端网络模块

(一)、Connect 连接服务端

https://blog.csdn.net/qq_42139931/article/details/124091349?spm=1001.2014.3001.5502

(二)、Receive 接收并处理数据

https://blog.csdn.net/qq_42139931/article/details/124092588?spm=1001.2014.3001.5502

(三)、Send 发送数据

https://blog.csdn.net/qq_42139931/article/details/124094323?spm=1001.2014.3001.5502

(四)、Close 关闭连接

https://blog.csdn.net/qq_42139931/article/details/124094895?spm=1001.2014.3001.5502

本篇内容:

Send 发送数据:

首先定义写入队列writeQueue,并将writeQueue在初始化函数Init中进行初始化:

代码语言:javascript复制
//写入队列
private static Queue<ByteArray> writeQueue;

Send回调函数中会判断写入队列是否还有数据,如果写入队列不为空,继续发送数据:

代码语言:javascript复制
//发送数据
public static void Send(IExtensible proto)
{
    //状态判断
    if (socket == null || !socket.Connected) return;
    if (isConnecting || isClosing) return;
    //数据编码
    byte[] nameBytes = ProtoUtility.EncodeName(proto);
    byte[] bodyBytes = ProtoUtility.Encode(proto);
    int len = nameBytes.Length   bodyBytes.Length;
    byte[] sendBytes = new byte[2   len];
    //组装长度
    sendBytes[0] = (byte)(len % 256);
    sendBytes[1] = (byte)(len / 256);
    //组装名字
    Array.Copy(nameBytes, 0, sendBytes, 2, nameBytes.Length);
    //组装消息体
    Array.Copy(bodyBytes, 0, sendBytes, 2   nameBytes.Length, bodyBytes.Length);
    //写入队列
    ByteArray ba = new ByteArray(sendBytes);
    int count = 0;
    lock (writeQueue)
    {
        writeQueue.Enqueue(ba);
        count = writeQueue.Count;
    }
    //Send
    if (count == 1)
    {
        socket.BeginSend(sendBytes, 0, sendBytes.Length, 0, SendCallback, socket);
    }
}
//Send回调
private static void SendCallback(IAsyncResult ar)
{
    //获取State、EndSend的处理
    Socket socket = (Socket)ar.AsyncState;
    //状态判断
    if (socket == null || !socket.Connected) return;
    //EndSend
    int count = socket.EndSend(ar);
    //获取写入队列第一条数据
    ByteArray ba;
    lock (writeQueue)
    {
        ba = writeQueue.First();
    }
    //完整发送
    ba.readIdx  = count;
    if (ba.length == 0)
    {
        lock (writeQueue)
        {
            writeQueue.Dequeue();
            ba = writeQueue.Count > 0 ? writeQueue.First() : null;
        }
    }
    //继续发送
    if (ba != null)
    {
        socket.BeginSend(ba.bytes, ba.readIdx, ba.length, 0, SendCallback, socket);
    }
    //正在关闭
    else if (isClosing)
    {
        socket.Close();
    }
}

Close 关闭连接:

封装关闭连接的函数,首先进行状态的判断,如果socket为空或着没有连接,return;如果正在连接,return;判断如果还有数据正在发送,将isClosing标志位设为true,否则关闭socket,并发布消息:

代码语言:javascript复制
/// <summary>
/// 关闭连接
/// </summary>
public static void Close()
{
    //状态判断
    if (socket == null || !socket.Connected) return;
    if (isConnecting) return;
    //还有数据在发送
    if (writeQueue.Count > 0)
    {
        isClosing = true;
    }
    //没有数据在发送
    else
    {
        socket.Close();
        Messenger.Publish("关闭连接");
    }
}

参考资料:《Unity3D网络游戏实战》(第2版)罗培羽 著

0 人点赞