Python网络编程(二)

在上篇文章中,我们了解了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库,这个就不用多说了

1
import 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()

这个程序实践过程中很明显的会出现很多不可预料的错误,要解决这些只能更详细的学习代理的协议,但是简单的思路还是没错的

文章作者: Somnus
文章链接: https://nikoeurus.github.io/2018/07/24/Python%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B(%E4%BA%8C)/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Somnus's blog