通过TCP选择JSON的传输

时间:2011-07-04 16:16:49

标签: json websocket streaming multipart ldjson

我正在编写一个简单的流式JSON服务。它由间歇性发送的JSON消息组成,持续很长一段时间(数周或数月)。

通过普通TCP套接字发送多个JSON消息的最佳做法是什么?

我看过的一些替代方案(及其缺点)是:

  1. 换行符分隔JSON - 缺点:JSON中的换行符需要转义或禁止
  2. websocket灵感来自0x00 0xff框架 - 缺点:它现在是二进制,而不是utf-8了
  3. 真正的websockets - 缺点:缺少(opensource)websocket 客户端
  4. http multipart http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html - 缺点:客户支持不完整?
  5. 没有分隔符 - 缺点:分块需要JSON解析(不能仅仅因为字符串中的curlies而计算curlies)
  6. 有没有一种好的,或至少是完善的方法呢?

5 个答案:

答案 0 :(得分:12)

我的前两个选项是:

  1. 执行早期TCP协议的操作:发送一条消息(在您的情况下为JSON对象)并关闭连接。客户端检测到它并重新打开以获取下一个对象。

    • 专业:非常容易解析,没有发送额外(内容)字节。任何数据丢失意味着只丢失一个对象。如果你能坚持下去,就不需要为你的应用添加重新传输。
    • 缺点:如果发送(大量)(非常)小对象,则三包TCP握手会增加延迟。
  2. 执行chunked-mode HTTP的操作:首先发送JSON对象中的字节数,换行符(HTTP中的CRLF)和JSON对象。客户端只需计算字节数就可以知道下一个字节何时成为下一个对象。

    • 专业人士:你保留了一条长寿的流。
    • 缺点:一些额外的字节,你必须保持一个长期存在的流,所以意外断开和重新连接必须作为例外事件处理,需要建立一些握手以继续失败。

答案 1 :(得分:5)

当您想要提供浏览器客户端时,最接近原始TCP的是WebSockets。

WebSockets有足够的动力,浏览器​​供应商将提高支持(Chrome 14和Firefox 7/8支持最新的协议草案),并且广泛的客户端和服务器框架将支持它。

已经有几个开源客户端库,包括Autobahn WebSocket

如果你想为自己烘焙一些东西(在原始TCP之上),我会为你的JSON消息推荐一种长度为前缀的格式,即Netstrings

免责声明:我是高速公路的作者并为Tavendo工作。

答案 2 :(得分:1)

我已经编纂了我和其他一些开发人员正在做的事情:

http://en.wikipedia.org/wiki/Line_Delimited_JSON

它具有与netcat / telnet兼容的优点。

另请参阅:http://ndjson.org/

答案 3 :(得分:1)

您可以使用Server-Sent Events

var source = new EventSource('/EventSource');

source.onmessage = function(e) {
  var data = JSON.parse(e.data);
  console.log(e.data);
};

source.onopen = function(e) {
  console.log('EventSource opened');
};

source.onerror = function(e) {
  console.log('EventSource error');
};

答案 4 :(得分:0)

消息的四个字节的第一个字节可以是32位整数,指示消息的大小(以字节为单位)。然后,接收者应遵循以下步骤:

  1. 读取数据的前四个字节,并找出读取整个消息所需的确切字节数。
  2. 阅读其余消息并将其反序列化为JSON

C#中的发件人代码:

        public void WriteMessage(Packet packet) {
        // Convert the object to JSON
        byte[] message = Encoding.UTF8.GetBytes(packet.Serialize());

        // Serialize the number of characters
        byte[] messageLength = BitConverter.GetBytes(message.Length);

        // Build the full message that will hold both the size of the message and the message itself
        byte[] buffer = new byte[sizeof(int) + message.Length];

        Array.Clear(message, 0, message.Length);

        // Print the size into the buffer
        for (int i = 0; i < sizeof(int); i++)
        {
            buffer[i] = messageLength[i];
        }

        // Print the message into the buffer
        for (int i = 0; i < message.Length; i++)
        {
            buffer[i + sizeof(int)] = message[i];
        }

        // Send it
        stream.Write(buffer, 0, buffer.Length);
    }