编程文汇

unty中如何使用websocket协议连接服务器

现有库

首先,我们要使用现有成熟的代码库,比如:

websocket-sharp使用示例

这里我选用了websocket-sharp,因为它的api简洁明了,也有onclose onopen事件,这就足够了:

        using (var ws = new WebSocket("ws://127.0.0.1:8080/game"))
        {
            ws.OnMessage += (sender, e) =>
                Console.WriteLine("Laputa says: " + e.Data);

            //以下操作都是同步的,会阻塞当前线程,如果是MonoBehavior调用,会阻塞主线程,严重降低帧率,所以实际环境用要使用带有async的异步方式。
            ws.Connect();
            //发送二进制消息,服务器接收的时候要区分二进制消息和文本消息,
            ws.Send(UTF8Encoding.UTF8.GetBytes("abc"));
            ws.Send(UTF8Encoding.UTF8.GetBytes("abc"));
            ws.Send(UTF8Encoding.UTF8.GetBytes("abc"));
            //发送文本消息
            ws.Send("hi");
            ws.Close();
        }

断线重连

这个库的断线重连做的也挺好,close之后,可以再次connect,就重连了。

public class NetTest : MonoBehaviour
{
    WebSocket ws;

    private void ConnecteToServer()
    {
        if (ws == null)
        {
            ws = new WebSocket("ws://127.0.0.1:8080/game");
            ws.OnMessage += (sender, e) =>
                Console.WriteLine("Laputa says: " + e.Data);
        }

        ws.Connect();
    }

    private void OnEnable()
    {
        ConnecteToServer();
    }

    private void OnDisable()
    {
        ws?.Close();
    }

}

把上面面这个类,附加到场景中的GameObject上,启用、禁用这个GameObject时,就可以在服务器上看到它建立连接、断开连接。所以,要断线重连,我们只需要在ws.OnClose事件中再次调用ConnecteToServer即可。

不要多次注册事件处理器

ws.OnMessage += (sender, e) {}
要注意类似的事件处理器的注册,千万不要重复,不然,一个事件触发后,可能会被重复处理。在这里
ConnecteToServer中用 if (ws == null)做了判断,如果去掉这个判断,反复的点启用禁用,就会出现重复处理的情况。

常见的顾虑

  1. 会粘包吗?
    在普通的socket通信中,我们需要考虑粘包问题,因为多个逻辑数据包可能会被打包成一个物理包一次发送过来。此时接收方需要把它拆开。同时一个大的逻辑包,也会被分成多个小的物理包发送出去,接收方需要把它们重组为逻辑包。websocket中不存在这个问题,因为协议中对包的长度有明确的定义,任何websocket实现都已经对这个问题进行了处理。所以,对于使用者来说省了很多事。
  2. 可以在同一个连接中同时使用文本消息和二进制消息么?
    答案是可以!!见上面的例子。其次,消息的类型是由websocket的每个包自己定义的,与整个链接没有关系。