字节协议理解和处理

字节协议理解和处理

理解字节协议

做web的开发的程序员,经常接触http协议,http协议因为已经在多个框架中进行了实现,所以不需要距离理解http协议是如何,
建立在,tcp/ip协议上实现的。仅仅需要知道,一些关于http状态码,这就成了他们对http协议的理解。

当然我们这里暂时不说http协议的具体问题,只是由http协议引出,字节协议。

http协议

创建一个socket server 服务器,在浏览器输入服务器地址和端口,可以看到服务器返回数据。

这个是最简单的webscoket,不需要处理client发送过来的数据,仅仅在访问时候,将服务端数据返回。

python http 服务器端代码

运行python 代码,启动服务器,浏览器输入:http://127.0.0.1:5000/

可以看到返回

Hello, World!asdfasdf

再看看服务端python代码:

#!-*-coding-utf8-*-
import socket

HOST, PORT = '', 5000

HOST = ''
PORT = 5000

"""http proto test"""

listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind((HOST, PORT))
listen_socket.listen(100)


print 'Serving HTTP on port %s ...' % PORT

while True:
    client_connection, client_address = listen_socket.accept()
    print "client_connection", client_connection, client_address

    request = client_connection.recv(1024)
    print "request",request

    http_response = """
HTTP/1.1 200 OK
Hello, World!asdfasdf
"""
    client_connection.sendall(http_response)
client_connection.close()

http_response 这个字符串最终被发送给了客户端,也就是浏览器,浏览器最终展示出来的结果只有。

Hello, World!asdfasdf

也就是说明:

HTTP/1.1 200 OK

这行,被浏览器处理,不会显示在网页上。我们去掉这行时候,是否还能展示Hello, World!asdfasdf,可以自己测试一下。

当然,这样的协议看似很简单。就是带上特殊的字符串。然后在返回值填写。不需要考虑字节协议。

当然上面仅仅说明了http的部分协议,了解一下就行。

换行符协议

通俗的讲当遇到换行符,表示客户端发送消息结束,服务端处理消息,然后返回将消息以换行符结尾,返回客户端,客户端收到
消息,然后根据换行符截断消息,从而得到服务端具体发送数据。

过程如下:

client -> send -> 换行符(\n)结束的消息
server -> recv -> 收取2014字节的消息,查看消息中是否有换行符(\n),如果有,就认为已经收到了完整的消息,
如果没有,就继续接收 1024个消息,直到收到消息中有换行符,我们认为我们收完整的消息。
从换行符开始阶段之前的数据,就是客户端,发送的一条完整消息。

client伪代码实现:

data = "message\n"
client.start()
client.send(data)
server_msg = ""
while True:
    recv_msg = client -> recv(1024) 
    if "\n" in recv_msg:
        server_msg = recv_msg + server_msg
        break
print data        
client.close()

server伪代码实现:

server.start()
while True:
    recv_msg = server.recv(1024)
    server.send(recv_msg)

特殊字符分割协议

使用字符分割,一般统称为字符协议(非专业术语,个人随意编撰)。

当然你可以定义自己的字符协议,比如使用“—”或者“$$$”分割等。

假设有如下情况:

  • 发送的字符中本来就含有这些特殊字符,判断时候,就会导致消息不完整

    例如分割符号为“—” ,发送的消息体中,也有“—–”,这个时候,程序就会报错。

  • 字符分割会发送无用的字符,占用空间影响效率(其实影响微乎其微)

  • 并不是所有发送的数据都是字符串,使用字符穿分割,可能出现很特殊的bug,比例传送图片或者视频数据

  • 非字符信息发送,需要二进制转换成字符信息,才能确定是否消息结束,当确认消息结束之后,需要再将字符消息转成二进制,保消息可以被解析。

对于上述的问题,就需要设计更加严谨的消息协议,应用余对应的场景。

二进制字符长度定义协议

我们有如下的需求:

发送端:

发送一个消息,我们会告诉接收端,这个消息多长,还有消息的类型。

接收端:

收取固定长度1014个字节的消息,当前消息长度在固定位置已经给出。在消息解析时候,按照发送过来的长度解析。

协议设计

消息长度(head) 消息数据(body)

*—————- ———

8                 body 

*—————- ———

long long的最大值:9223372036854775807

long long的最小值:-9223372036854775808

设计概要

消息头部放置本次消息的长度,长度之后的字节表示消息体

具体设计

  • 首字符8位字节表示本次消息长度,最大的表示长度是9223372036854775807。
  • 消息体,应该不会有消息超过长度

具体代码实现服务端和客户端

服务端

客户端

客户端接收方式

  • 先接收8个字节的头,知道消息体长度
  • 接收消息体长度的数据。

ps: 同样你可以接收固定长度,然后拼接数据