字节协议理解和处理
理解字节协议
做web的开发的程序员,经常接触http协议,http协议因为已经在多个框架中进行了实现,所以不需要距离理解http协议是如何,
建立在,tcp/ip协议上实现的。仅仅需要知道,一些关于http状态码,这就成了他们对http协议的理解。
当然我们这里暂时不说http协议的具体问题,只是由http协议引出,字节协议。
http协议
创建一个socket server 服务器,在浏览器输入服务器地址和端口,可以看到服务器返回数据。
这个是最简单的webscoket,不需要处理client发送过来的数据,仅仅在访问时候,将服务端数据返回。
运行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: 同样你可以接收固定长度,然后拼接数据