1.简介
本来打算再写一篇这个系列的文章也要和小伙伴或者童鞋们说再见了,可是有人留言问WebSocket包和小程序的包不会抓,那就关于这两个知识点宏哥就再水两篇文章。
2.什么是Socket?
在计算机通信领域,socket 被翻译为“套接字”(套接字=主机+端口号),它是计算机之间进行通信的一种约定或一种方式。通过 socket这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read关闭close”模式来操作。
我的理解就是Socket就是该模式的一个实现,它只是提供了一个针对TCP或者UDP编程的接口:即socket是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。
socket抽象层在网络中的位置图解,如下图所示:
3.Socket通信流程
Socket通信流程,如下图所示:
根据socket通信基本流程图,总结通信的基本步骤:
服务器端:
第一步:创建一个用于监听连接的Socket对像;
第二步:用指定的端口号和服务器的ip建立一个EndPoint对像;
第三步:用socket对像的Bind()方法绑定EndPoint;
第四步:用socket对像的Listen()方法开始监听;
第五步:接收到客户端的连接,用socket对像的Accept()方法创建一个新的用于和客户端进行通信的socket对像;
第六步:通信结束后一定记得关闭socket;
客户端:
第一步:建立一个Socket对像;
第二步:用指定的端口号和服务器的ip建立一个EndPoint对像;
第三步:用socket对像的Connect()方法以上面建立的EndPoint对像做为参数,向服务器发出连接请求;
第四步:如果连接成功,就用socket对像的Send()方法向服务器发送信息;
第五步:用socket对像的Receive()方法接受服务器发来的信息 ;
第六步:通信结束后一定记得关闭socket;
4.python实现一个客户端与服务端的通信
4.1函数
Socket对象方法:
服务端:
函数 | 描述 |
---|---|
.bind() | 绑定地址关键字,AF_INET下以元组的形式表示地址。常用bind((host,port)) |
.listen() | 监听TCP,可以挂起的最大连接数,该值至少为1,一般设为5即可 |
.accept() | 被动接受TCP客户端的连接 |
客户端: |
函数 | 描述 |
---|---|
.connect() | 初始化服务器连接 |
.connect_ex() | 是对connect()函数的扩展,当出错时返回出错码,不报异常 |
其它函数: |
函数 | 描述 |
---|---|
.recv() | 接收数据,数据以字符串的形式返回,bufsize指定接收的最大数据量。 |
.send() | 发送数据,将string中的数据发送到连接的套接字,返回值是要发送的字节数量,通常使用.encode()函数对数据进行转码 |
.senddall() | 发送完整的数据,在返回之前会尝试发送所有数据,成功返回None,失败则抛出异常。 |
.recvfrom() | 与recv()函数类似,不同的是返回值是(data,address),其中data是包含接收数据的字符串,address是发送数据的套接字地址。 |
.sendto() | 发送UDP数据,将数据发送到套接字,形式是(ipaddr,port)的元组。 |
.close() | 关闭套接字 |
4.2服务端
使用socket函数来创建一个socket对象,并设置一个socket服务,然后通过bind(hostname,port)函数来指定一个端口,使用socket对象的accept方法,等待客户端的连接,并返回connection对象。
具体步骤为:
#创建服务端套接字 serversocket=socket() #把地址绑定到套接字 serversocket.bind() #对连接进行监听 serversocket.listen() #使用一个while进行循环,并接收客户端的连接 while True: serverclient=serversocket.accept() while True: #接收已发送 serverclient.recv() serverclient.send() #关闭客户端套接字 serverclient.close() #关闭服务端套接字 serversocket.close()
4.3具体代码实现
实现功能:通过while实现循环接收客户端发送的数据,并对客户端发送的数据进行显示并返回给客户端数据,返回给客户端的数据信息后加入时间戳。新建一个文件server.py。
import socket import sys import time serversocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM) host=socket.gethostname()#获取本地主机名 port=9999 #绑定端口号 serversocket.bind((host,port)) #设置最大连接数 serversocket.listen(5) while True: print('服务器启动,监听客户端链接') clientsocket,addr=serversocket.accept() print('链接地址:%s' % str(addr)) while True: try: data=clientsocket.recv(1024) except Exception: print('断开的客户端:',addr) break print('客户端发送内容:',data.decode('utf-8')) reply=input('回复:').strip() if not reply: break msg=time.strftime('%Y-%m-%d %X')#获取结构化时间戳 msg1='[%s]:%s'% (msg,reply) clientsocket.send(msg1.encode('utf-8')) clientsocket.close() serversocket.close()
4.4客户端
创建一个客户端用来连接以上服务的的服务,使用socket.connect()方法打开一个TCP连接到主机,连接后可以从服务端获取数据,在操作完成后关闭连接。
具体步骤为:
#创建客户端的套接字 client=socket() #尝试连接服务器 client.connect() #发送并接收数据 client.send() client.recv() #关闭客户端套接字 client.close()
4.5具体代码实现
新建一个文件client.py。
import socket import sys s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) host=socket.gethostname() port=9999 s.connect((host,port)) while True: data= input('>>').strip() if not data: break s.send(data.encode('utf-8')) msg=s.recv(1024) if not msg: break print(msg.decode('utf-8')) s.close()
4.6测试
使用cmd命令行中打开到代码所在文件目录,执行python 服务端文件名.py,再另打开一个cmd命令界面执行 python 客户端文件名.py。
1.在cmd中运行服务端代码,运行结果,如下图所示:
2.在cmd中运行客户端代码,运行结果,如下图所示:
好了到此就实现了,但是宏哥抓不到包,不知道是不是因为服务端和客户端都在宏哥本地一台电脑的原因,算了宏哥直接网上找了一个在线的演示给大家。
5.实战抓WebSocket包
由于时间关系,宏哥没有尝试将客户端和服务器分开看看是否可以抓到包,然后在网上找了一个地址:http://coolaf.com/tool/chattest 演示给大家。具体操作步骤如下:
1.Fiddler V4.5以上版本,rules>customize rules,加入如下代码,把websocket通信日志加入log,如下图所示:
2.class Handler 类中添加,添加的代码如下:
static function OnWebSocketMessage(oMsg: WebSocketMessage) { // Log Message to the LOG tab FiddlerApplication.Log.LogString(oMsg.ToString()); }
3.打开PC版的聊天室(宏哥提供的演示地址),并刷新Fiddler,会看到一个WS图标的请求,双击该请求,右边会出现websocket的tab页,如下图所示:
PC版在线聊天,如下图所示:
Fiddler抓的WebSocket包,如下图所示:
4.切换到log tab页可以看到通信的数据往来,如下图所示:
5.通过F12也可以看到websocket的请求信息,进入聊天室后,F12>network>滤斗(放大镜左边的这个红色图标)>WS,双击name里边这个,即展开相关的详情,在详情里选中某条数据,底部会进一步显示全部信息,如下图所示:
6.小结
将那段代码保存后就可以在Fiddler右边栏的Log标签里,看到WebSocket的数据包。到了这里,还有一个情况要说明,就算是有工具可以抓到WebSocket中的包,看到的也不一定是明文。这个要看传输的水是什么,如果是普通水那谁都可以分析;但如果是水银,那这个分析水的设备很可能就显示乱码了。 所以也就有同学明明使用了可以抓WebSocket包的程序,却抓出来的是乱码。那是因为别人传输的是二进制数据流(比如AMF包),而不是JSON之类的对人类可读的明文。而宏哥演示的网址是用于测试的因此没有考虑安全进行加密,所以使用的是明文,大家可以看到客户端和服务端相互发送的信息内容,关于如何加密宏哥在这里就不做赘述了因为它不是今天的重点内容。
6.1关于websocket
1.HTML5提供的在单个TCP上运行的全双工通讯协议(应用层协议)
2.客户端和服务器之间只需要进行一次握手就能够实现双向通讯,进行数据传输
3.相比较Ajax轮询机制需要不断地从客户端间隔性发送请求,传输不必要的头部数据,消耗大量的带宽,websocket节省了服务资源和宽带
4.通过send()方法发送数据给客户端,客户端通过onmessage接收服务器返回的数据