【问题标题】:Gorilla Websocket not receiving message大猩猩 Websocket 没有收到消息
【发布时间】:2018-09-05 08:08:09
【问题描述】:

我正在用 Golang 构建一个与 Gorilla websockets 通信的网关。

我在 Ubuntu 16.04 上运行它,目前正在使用 .NET 控制台应用程序对其进行测试。

在 Windows 上使用 Wireshark 并在 Ubuntu 上使用嗅探器确定 消息从 Windows 客户端正确发送并由 Ubuntu 机器接收

然而,在我的代码中,有时在一些成功消息之后,有时在没有消息之后,我的网关无法读取消息(仍然坐在_, msg, errCon := conn.ReadMessage()

输出示例如下:

2018/03/27 02:38:06 等待消息... 2018/03/27 02:38:07 收到消息:main.AdminRequest{Data:"{\​​"SomeDataHeader\":\"SomeData\"}", 请求者:“user”,类型:“JustDoSomethingRequest”,Ukey:“talca”} 2018/03/27 02:38:07 {"SomeDataHeader":"SomeData"} 2018/03/27 02:38:07 等待留言...

正如我之前所说,它可能会收到一些这样的消息,但是,尽管两端的网络流量仍在继续,但不会再收到消息了

我对 Golang 还很陌生,并且假设我错过了一些东西。

为了简洁起见,我在下面的代码中删除了错误处理等,但这是一个失败代码的示例。

编辑根据要求,我在下面添加了 Golang 完整代码和 C# 客户端代码(尽管如我所述,Wireshark 和 snifit 已确定数据正在通过网络传输)

package main

import (
    "fmt"
    "net/http"
    "github.com/gorilla/websocket"
    "encoding/json"
    "log"
)

var upgrader = websocket.Upgrader{ ReadBufferSize:  1024, WriteBufferSize: 1024,
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

type AdminRequest struct {
        Data      string `json:"Data"`
        Requestor string `json:"Requestor"`
        Type      string `json:"Type"`
        Ukey      string `json:"Ukey"`
    } 

func main() {

    http.HandleFunc("/a", func(w http.ResponseWriter, r *http.Request) {
        var conn, _ = upgrader.Upgrade(w, r, nil)

        go func(conn *websocket.Conn) {
            for {
                _, _, err := conn.ReadMessage()
                if err != nil {         
                    log.Println("Close: "+ err.Error())
                    conn.Close()
                    return
                }
            }
        }(conn)


        go func(conn *websocket.Conn) {
            for {

                log.Println("Awaiting Message ...")
                _, msg, errCon := conn.ReadMessage()

                if errCon != nil {
                    log.Println("Read Error:", errCon)
                    break
                }

                log.Println("Message received: ")

                var r AdminRequest

                if err := json.Unmarshal(msg, &r); err != nil {

                    log.Println("Error: " + err.Error());
                    return;
                }

                fmt.Printf("%#v\n", r)
                log.Println(r.Data);
            }           
        }(conn)

    })

    http.ListenAndServe(":3000", nil)
}

C#代码:

public class Client : IDisposable
    {
        private ClientWebSocket _socket;


        string _address;
        int _port;
        public Client(string address)
        {
            _address = address;

            _socket = new ClientWebSocket();
        }

        public async void SetupForReceivingStuffs()
        {
            while (_socket.State == WebSocketState.Open)
            {
                ArraySegment<byte> receivedBytes = new ArraySegment<byte>(new byte[1024]);
                WebSocketReceiveResult result = await _socket.ReceiveAsync(receivedBytes, CancellationToken.None);

                Console.WriteLine(Encoding.UTF8.GetString(receivedBytes.Array, 0, result.Count));
            }
        }

        public async void SetupForSendingStuffs(ConcurrentQueue<AdminRequest> queue)
        {
            while (_socket.State == WebSocketState.Open)
            {
                AdminRequest next;

                while (queue.Count > 0)
                {
                    if (queue.TryDequeue(out next))
                    {
                        await Send(next);
                    }
                }

                await Task.Yield();
            }
        }

        public async Task Connect()
        {
            while (_socket.State != WebSocketState.Open)
            {
                try
                {
                    _socket = new ClientWebSocket();
                    await _socket.ConnectAsync(new Uri(_address), CancellationToken.None);

                    Console.WriteLine("Socket state: " + _socket.State);
                }
                catch (Exception ex)
                {
                    //Not getting hit
                    Console.WriteLine(ex.Message);
                    Console.WriteLine(ex.StackTrace);
                }
            }
        }



        public Task Send<TData>(TData data)
        {
            string text = JsonConvert.SerializeObject(data);

            var encoded = Encoding.UTF8.GetBytes(text);
            var buffer = new ArraySegment<Byte>(encoded, 0, encoded.Length);

            return _socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
        }


        public void Dispose()
        {
            _socket.Dispose();
        }
    }

调用者:

class Program
{
    static ConcurrentQueue<AdminRequest> _toSend;

    static void Main(string[] args)
    {
        _toSend = new ConcurrentQueue<AdminRequest>();

        Client client = new Client("ws:/(myip):(myport)/a");
        client.Connect().Wait();

        //client.SetupForReceivingStuffs();
        client.SetupForSendingStuffs(_toSend);

        WriteInstructions();

        LoopAuto();

        Console.WriteLine("Bye");
    }

    private static void LoopAuto()
    {
        DateTime nextMessage = DateTime.Now;

        while (true)
        {

            if (DateTime.Now < nextMessage) continue;
            Console.WriteLine("Next");
            nextMessage = DateTime.Now.AddSeconds(2);

            _toSend.Enqueue(new AdminRequest
            {
                Data = "{\"SomeDataHeader\":\"SomeData\"}",
                Requestor = "user",
                Type = "JustDoSomethingRequest",
                Ukey = "talca"
            });
        }
    }

    private static ConsoleKeyInfo LoopManual()
    {
        ConsoleKeyInfo info;
        do
        {
            info = Console.ReadKey(true);

            if (info.KeyChar == '1')
            {
                _toSend.Enqueue(new AdminRequest
                {
                    Data = "{\"SomeDataHeader\":\"SomeData\"}",
                    Requestor = "user",
                    Type = "JustDoSomethingRequest",
                    Ukey = "talca"
                });
            }
            else if (info.KeyChar == 'i')
            {
                WriteInstructions();
            }

        } while (info.KeyChar != 'x');

        return info;
    }

    private static void WriteInstructions()
    {
        Console.WriteLine("1. Send New Message");
        Console.WriteLine("i. Instructions (these lines)");
        Console.WriteLine("x: Exit");
    }
}

【问题讨论】:

  • 你可以试试,err := conn.WriteMessage(1, []byte("test message")) 然后在发送到客户端时检查错误
  • @CeriseLimón 我已经添加了来自服务器端(golang)和客户端(.NET)的所有代码
  • @Pizzalord 我正在检查原始代码(检查上面的编辑),但为了简洁起见,最初将其编辑了。我现在变得更加冗长了。

标签: go websocket gorilla


【解决方案1】:

应用程序运行两个循环读取消息的 goroutine。第一个对收到的消息不做任何事情。第二个解析并记录消息。您看不到任何输出,因为第一个 goroutine 正在接收消息。

第一个 goroutine 似乎没有任何用途。 删除第一个 goroutine 以解决问题。

删除第一个 goroutine 也修复了数据竞争。 Concurrent reads on a websocket connection are not supportedrace detector 将报告此问题。

这是更新后的代码以及其他修复和改进。网络/http 服务器 将处理程序称为每个连接的 goroutine。使用 tha goroutine 而不是启动另一个 goroutine。使用 websocket 包的 JSON 辅助方法。

package main

import (
    "fmt"
    "net/http"
    "github.com/gorilla/websocket"
    "encoding/json"
    "log"
)

var upgrader = websocket.Upgrader{ ReadBufferSize:  1024, WriteBufferSize: 1024,
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

type AdminRequest struct {
        Data      string `json:"Data"`
        Requestor string `json:"Requestor"`
        Type      string `json:"Type"`
        Ukey      string `json:"Ukey"`
    } 

func wsHandler(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Println(err)
        return
    }
    defer conn.Close()
    for {
        var r AdminRequest
        if err := conn.ReadJSON(&r); err != nil {
            log.Println(err)
            break
        }
        fmt.Printf("%#v\n", r)
        log.Println(r.Data);
    }           
}

func main() {
    http.HandleFunc("/a", wsHandler)
    http.ListenAndServe(":3000", nil)
}

【讨论】:

  • 非常感谢,我正在拔头发。我会给它一个测试,然后将你标记为答案。这一切都说得通,但对 golang 来说还是新手,对我来说仍然不是那么直观
  • 回答第一个 goroutine 的要点是,如果客户端请求/退出,则关闭连接,但我可以通过检查读取的 JSON 上的错误来轻松处理。跨度>
猜你喜欢
  • 2018-06-08
  • 2021-04-08
  • 2014-03-15
  • 2015-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-20
  • 2014-11-24
相关资源
最近更新 更多