引言
最近因为Lab需求,需要写一个转发服务器消息的节点。本来打算用C++写,但是查了一下发现一点也不简洁…还是用python写吧,反正只是一个不复杂的work。还有现成的包可以调,多舒服啊~
通信协议
计算机通信协议是对那些计算机必须遵守以便彼此通信的规则的描述。大白话就是通信双方共同约定的交流方式(怎么建立通信,数据包格式等),是说中文还是说英文啊,老弟?
TCP/IP
TCP/IP 指传输控制协议/网际协议 (Transmission Control Protocol / Internet Protocol)。TCP/IP 定义了电子设备(比如计算机)如何连入因特网,以及数据如何在它们之间传输的标准。
TCP 用于应用程序之间的通信。
当应用程序希望通过 TCP 与另一个应用程序通信时,它会发送一个通信请求。这个请求必须被送到一个确切的地址(IP和端口)。在双方“握手”之后,TCP 将在两个应用程序之间建立一个全双工的通信。这个全双工的通信将占用两个计算机之间的通信线路,直到它被一方或双方关闭为止。上述过程通常称作三次握手机制。
下面先看看python中的简单实现方法:
客户端:
#!/usr/bin/env python
HOST = '127.0.0.1' # or 'localhost'
PORT = 9999
BUFSIZ =1024
ADDR = (HOST,PORT)
tcpCliSock = socket(AF_INET,SOCK_STREAM)
tcpCliSock.connect(ADDR) #l链接服务器
while True:
data1 = input('>')
#data = str(data)
if not data1:
break
tcpCliSock.send(data1.encode()) #发送的数据需要编码为bytes
data1 = tcpCliSock.recv(BUFSIZ) #从服务器接收消息
if not data1:
break
print(data1.decode('utf-8')) #将接收到的消息解码
tcpCliSock.close()
python中提供的socket套接字包可以让我们很方便的实现不同通信协议的通信数据传输。
Socket
socket又称套间字或者插口,是网络通信中必不可少的工具。其工作过程主要分为创建套接字、链接服务器、通信、关闭几个过程。其中创建套接字这一步需要指定通信协议、socket类型。协议域:AF_INET->IPv4;AF_INET6->IPv6 。socket类型:SOCK_STREAM->TCP;SOCK_DGRAM->UDP
UDP
UDP方式同TCP方式的建立过程几乎一模一样,只是将
tcpCliSock = socket(AF_INET,SOCK_STREAM)
改为了
tcpCliSock = socket(AF_INET,SOCK_DGRAM)
不同的是,udp 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。只是每次从服务器获取消息时,需要先向服务器发送消息。
编解码
服务器和本地客户端都是python实现的话,用python实现通信确实很方便简洁。但是如果服务器端不是python写的,可能数据传输过来简单的用decode来解码,可能就会发现数据和发出的时候的不一样了。因为C/C++是有数据对齐的,但是python可不管那么多。所以要实现python同C、C++发出来的数据需要指定解码的格式,不然怎么知道b’11111111’原来对应的是什么数?
struct包解决了这个问题!!!!
strcut.unpack(format,buff)# format是指定的解码格式,buff是收到的数据。是bytes为单位的
一个简单例子:
import struct
# native byteorder
buffer = struct.pack( "ihb" , 1 , 2 , 3 )
print repr ( buffer )
print struct.unpack( "ihb" , buffer )
# data from a sequence, network byteorder
data = [ 1 , 2 , 3 ]
buffer = struct.pack( "!ihb" , * data)
print repr ( buffer )
print struct.unpack( "!ihb" , buffer )
Output:
'\x01\x00\x00\x00\x02\x00\x03'
( 1 , 2 , 3 )
'\x00\x00\x00\x01\x00\x02\x03'
( 1 , 2 , 3 )
详细的函数怎么用可以去python的官网文档查看:https://docs.python.org/3.5/library/struct.html
其中还有可以从指定位置开始按指定解码格式解码的函数和按指定解码格式不断迭代解码的函数。
结果
上述工作中最头痛的是python直接传输16进制数:比如0x3030。解决办法是:
bytes.formhex('3030')
即可得到对应的bytes,直接装入pack()函数即可。
结果就是应该完成了工作,等待进一步测试啦。