Asyncore
- 概念
Basic infrastructure for asynchronous socket service clients and servers. There are only two ways to have a program on a single processor do “more than one thing at a time”. Multi-threaded programming is the simplest and most popular way to do it, but there is another very different technique, that lets you have nearly all the advantages of multi-threading, without actually using multiple threads. it’s really only practical if your program is largely I/O bound. If your program is CPU bound, then pre-emptive scheduled threads are probably what you really need. Network servers are rarely CPU-bound, however. If your operating system supports the select() system call in its I/O library (and nearly all do), then you can use it to juggle multiple communication channels at once; doing other work while your I/O is taking place in the “background.” Although this strategy can seem strange and complex, especially at first, it is in many ways easier to understand and control than multi-threaded programming. The module documented here solves many of the difficult problems for you, making the task of building sophisticated high-performance network servers and clients a snap. - 使用
简单来说asyncore即是一个异步的socket封装,其中包含了很多异步调用的socket操作方法。具体使用方法可查阅官方文档~
protobuf
安装
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.11.2/protobuf-all-3.11.2.tar.gz
tar zxf protobuf-all-3.11.2.tar.gz
cd protobuf-3.11.2
./configure -prefix=/usr/local/
make && make install
验证是否安装成功
protoc --version
若报错执行 ldconfig
显示正常的版本号即可
使用
- 编辑协议.proto文件
syntax = "proto3";
package ProtoPac;
message AddressBook {
repeated Person people = 1;
}
message Person {
string name = 1;
int32 id = 2;
string email = 3;
float money = 4;
bool work_status = 5;
repeated PhoneNumber phones = 6;
MyMessage maps = 7;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message MyMessage {
map<int32, int32> mapfield = 1;
}
- 项目中引包
pip3 install protobuf==3.11.2
- 编辑add_person.py文件
from ProtoPac import addressbook_pb2
address_book = addressbook_pb2.AddressBook()
person = address_book.people.add()
person.id = 1
person.name = "AprilY"
person.email = "AprilY@qq.com"
person.money = 100000000.11
person.work_status = True
phone_number = person.phones.add()
phone_number.number = "123456"
phone_number.type = addressbook_pb2.MOBILE
maps = person.maps
maps.mapfield[1] = 1
maps.mapfield[2] = 2
# 序列化
serializeToString = address_book.SerializeToString()
print(serializeToString, type(serializeToString))
address_book.ParseFromString(serializeToString)
for person in address_book.people:
print("p_id{},p_name{},p_email{},p_money{},p_workstatu{}"
.format(person.id, person.name, person.email, person.money, person.work_status))
for phone_number in person.phones:
print(phone_number.number, phone_number.type)
for key in person.maps.mapfield:
print(key, person.maps.mapfield[key])
输出:
b'\n8\n\x06AprilY\x10\x01\x1a\rAprilY@qq.com% \xbc\xbeL(\x012\x08\n\x06123456:\x0c\n\x04\x08\x01\x10\x01\n\x04\x08\x02\x10\x02' <class 'bytes'>
p_id1,p_nameAprilY,p_emailAprilY@qq.com,p_money100000000.0,p_workstatuTrue
123456 0
1 1
2 2
协议安全工具
-
基础运行原理
before: [Client] <—> [Server]after: [Client] <—> [Proxy] <—> [Server]
开启一个中间代理,将原本客户端直接连接服务器的方式,客户端连接代理,代理转发信息给服务器的方式,在这个过程中,代理获取服务器和客户端之间的收/发包数据,并进行解析。
# coding=utf-8
import asyncore
import socket
import logging
# Server 专门用于接收客户端请求
from proto.base.util import GetId
bind_ip = {}
bind_ports = {}
class Proxy(asyncore.dispatcher):
def __init__(self, server_address, pCallback, param=None, server_port=None):
asyncore.dispatcher.__init__(self)
self.client = {}
self.server = {}
self.id = 0
if len(server_address) == 3:
self.server_port = server_address[2]
self.port = server_address[1]
else:
self.server_port = server_address[1]
self.port = server_address[1]
self.ip = server_address[0]
logging.info("ip=%s--------port=%d-----------server_port=%d" % (self.ip, self.port, self.server_port))
self.param = param
self.pCallback = pCallback
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.bind(("0.0.0.0", self.server_port))
self.listen(5)
# print("** start", pCallback.__name__, self.ip, self.port)
if server_port is None:
server_port = self.port
bind_ip[self.port] = (self.ip, int(server_port))
def handle_accept(self):
self.id = GetId()
client_proxy, addr = self.accept()
server_proxy = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_proxy.connect((self.ip, self.port))
param = []
for i in range(len(self.param)):
param.append(self.param[i])
param.append(self.id)
server_address = bind_ip[self.port]
client, server = self.pCallback(client_proxy, server_proxy, server_address, param)
self.client[self.id] = client
self.server[self.id] = server
运行逻辑
- 启动后,会创建一个Proxy类,创建后代理会在本地对一个端口进行监听,并且连接到服务器对应的端口。模拟本地的一个服务器。
- 游戏客户端连接本地的端口,往本地的端口发包,被监听着端口的代理获取到。
- 代理解包(从底层代码调用到handle_read读取),然后解析后会找到相应的响应函数对特定的协议数据进行响应(各Base类的on_protocol_handle方法)。
- 解析完之后,控制台输出协议信息,并重新打包后(handle_write方法)转发到服务器。
- 在此之上封装一层套壳逻辑对历史收发协议进行保存修改的操作,从而达到手动篡改协议并发包的目的。
具体代码就不贴了~
之后使用对应的类去执行不通服务的协议,比如说游戏中的网关服务(Portalserver)、登录服务(LoginServer)、游戏服务(GameServer)、房间服务(RoomServer)等。
如何解析使用协议就要看具体的场景。
引用
https://cloud.tencent.com/developer/article/1719013
https://www.cnblogs.com/tomato0906/articles/4777959.html
https://www.cnblogs.com/tomato0906/articles/4807774.html
https://blog.csdn.net/qq_41962612/article/details/128712838