在上篇文章中,我们了解了Python网络编程的基础模块socket,并利用threading模块实现了多线程处理以及模拟了代理的过程,这篇文章了解一下Python中更为实用,功能更加强大的socketserver模块,用法也更为简单,同时我们也试着实现模拟burp抓取http头部
socketserver库
python 3是将python 2中的SocketServer库的大写取消,即socketserver库
首先介绍一下socketserver库的五个重要的类:
1.BaseServe:这个类是模块里最基本的类,所有的类源头都来至于这个基类,但是他不是用于实例或使用的
2.TCPServer:这个类用于TCP/ip的socket通讯
3.UDPServer:这个类用于UDP的socket通讯
4.UnixStreamServer
5.UnixDatagramServer :使用的Unix - domain sockets通讯,并且只能Unix平台使用
可能看不太懂,无所谓,我们只需要关心它的基本使用方法即可
(1)首先我们先导入socketserver库,这个就不用多说了
(2)然后我们需要自定义一个类,用这个类来继承socketserver库中的BaseRequestHandler类,然后重写BaseRequestHandler类中的handle方法,其实就是自定义我们通讯的接收与发送过程
1 2 3 4 5 6
| class MyTCPServer(socketserver.BaseRequestHandler): def handle(self): self.data = self.request.recv(1024) print(bytes.decode(self.data)) self.reply = input('reply: ') self.request.sendall(str.encode(self.reply))
|
这里的self.request.recv()和self.request.sendall()其实就相当于我们socket模块中的recv和send方法
(3)接下来我们在主函数中使用socketserver的ThreadingTCPServer方法实例化一个对象server,传入元组(ip,端口)和我们定义的继承类,然后使用serve_forever()来启动服务
1 2 3
| if __name__=='__main__': server = socketserver.ThreadingTCPServer(('',6666),MyTCPServer) server.serve_forever()
|
可以看出,对比与socket库,我们简化了初始socket,绑定端口ip,开始监听的过程,只需要去规定发送与接收信息的流程,并且支持多线程,短短几行代码就可以实现我们之前通过复杂的代码实现的效果
下面附上一个简单的Server端和Client端的实例:
Server端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import socketserver
class MyTCPServer(socketserver.BaseRequestHandler): def handle(self): print('Connected By',self.client_address) self.request.send(str.encode('Welcome to TCPServer!')) while True: self.data = self.request.recv(1024) self.data = bytes.decode(self.data) if(self.data == 'exit'): print('Client',self.client_address,'has lost') break print('The data from',self.client_address,'is',self.data) self.reply = input('reply to client: ') self.request.send(str.encode(self.reply))
if __name__=='__main__': HOST = 'localhost' PORT = 6666 server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPServer) server.serve_forever()
|
Client端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from socket import *
c = socket(AF_INET,SOCK_STREAM) c.connect(('127.0.0.1',6666)) message = c.recv(1024) print(bytes.decode(message)) while True: data = input('data: ') if data == 'exit': c.send(str.encode(data)) break c.send(str.encode(data)) reply = c.recv(1024) print('The reply from TCPServer is',bytes.decode(reply)) c.close()
|
模拟burp抓取http包
想必大家都用过burp,它相当于一个我们使用的客户端与要访问的服务器之间的一个代理,我们要发送到服务器的http请求报文都会通过burp,被burp拦截下来,然后burp可以分析我们发送的http请求包头
在学习了socket后,我们可以试着模拟一下代理的过程,首先我们先试着抓取http请求
代码如下:
1 2 3 4 5 6 7 8 9 10
| from socket import *
s = socket(AF_INET,SOCK_STREAM) s.bind(('localhost',8080)) s.listen(5) sock,addr = s.accept() header = bytes.decode(sock.recv(1024)) print(header) sock.close() s.close()
|
代码很简单,就是利用socket库的基本方法,这里监听的是本地的8080端口,也就是说我们设置浏览器的代理地址是127.0.0.1,端口是8080
接下来启动程序,在浏览器中输入网址,监听到http包头
然后我们要想办法获取访问的主机名,这里利用正则匹配获得
1 2 3
| import re match = re.search(r'Host:\s(.*)\s',http) CHOST = match.group(1)
|
获取了访问的主机名,我们就可以连接至访问主机,然后将http包头发送给目标主机,再将目标主机返回的信息发回给本地主机,就可以实现代理了,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import socketserver import re from socket import *
def getHost(http): match = re.search(r'Host:\s(.*)\s',http) CHOST = match.group(1) return CHOST
class MyProxy(socketserver.BaseRequestHandler): def handle(self): self.http = self.request.recv(1024) self.http = bytes.decode(self.http) print(self.http) self.CHOST = getHost(self.http) c = socket(AF_INET,SOCK_STREAM) c.connect((self.CHOST,80)) c.send(str.encode(http)) response = [] while True: data = c.recv(1024) if data: response.append(data) else: break self.response = ''.join(response) self.sendall(self.response)
if __name__=='__main__': LHOST = 'localhost' LPORT = 8080 server = socketserver.ThreadingTCPServer((LHOST,LPORT),MyProxy) server.serve_forever()
|
这个程序实践过程中很明显的会出现很多不可预料的错误,要解决这些只能更详细的学习代理的协议,但是简单的思路还是没错的