共计 3310 个字符,预计需要花费 9 分钟才能阅读完成。
1、从语言的选择方向来说,因为我目的是要方便生活使用,希望能快速达到目的,如果用 C 和 C ++ 来说,工作量稍大些,于是选择了我还算熟悉的 python 语言
2、里面比较有意思的是在于数据的转发,代理既要承担 “ 送出去 ” 的任务,也要承担 “ 送回来 ” 的任务,思考了下数据结构的使用,使用了字典的方式,即 client->forward,forward->client,如果用 C 来实现的话,就是封装一个结构体,里边有客户端连接的 socket,也有传送回来的 forward sokcet
3、一旦接收到有客户端连接代理程序,代理程序马上向要转发的目的机器进行 TCP 连接的建立,同时将双方的 socket 信息成对保存在字典中
4、采用简单的 select 模型,主要是图个便利,当有活动的 socket 连接时,能马上检测到 socket 句柄的活动,从而从字典中找到对应的 socket 连接信息
总结:既然选择了写程序,碰到看不顺手,或操作麻烦的事情,就来个程序终结它,Orz!
技术没有所谓最好的语言,语言只是工具,但要用好,别伤了自己,在合理的事情上选择对的工具,让那些争论 PHP 是最好的语言的人浪费时间去吧。最后:上程序!!叮叮叮!
#coding=utf-8
import socket
import select
import sys
import threading
import time
import logging
import os
logsDir = "logs"
#目录不存在则创建
if not os.path.isdir(logsDir):
os.mkdir(logsDir)
#记录日志
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S',
filename='logs/logs.log',
filemode='a')
#C 的 IP 和端口
to_addr = ()
#最大连接数
maxConnetions = 32
class Proxy:
def __init__(self, addr):
self.proxy = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.proxy.bind(addr)
self.proxy.listen(maxConnetions)
self.inputs = {self.proxy:None}
self.route = {}
def serve_forever(self):
logging.info('proxy listen...')
while 1:
readable, _, _ = select.select(list(self.inputs.keys()), [], [])
for self.sock in readable:
if self.sock == self.proxy:
self.on_join()
else:
try:
data = self.sock.recv(8192)
except Exception, e:
logging.error(str(e))
self.on_quit()
continue
if not data:
self.on_quit()
else:
try:
self.route[self.sock].send(data)
except Exception, e:
logging.error(str(e))
self.on_quit()
continue
def on_join(self):
client, addr = self.proxy.accept()
logging.info("proxy client " + str(addr) + 'connect')
forward = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
forward.connect(to_addr)
except Exception, e:
logging.error(str(e))
client.close()
return
self.inputs [client] = None
self.inputs [forward] = None
self.route[client] = forward
self.route[forward] = client
# 删除连接
def on_quit(self):
ls = [self.sock]
if self.sock in self.route:
ls.append(self.route[self.sock])
for s in ls:
if s in self.inputs:
del self.inputs[s]
if s in self.route:
del self.route[s]
s.close()
if __name__ == '__main__':
proxy = Proxy(('',54321))
try:
with open('proxy.conf',"r") as fd:
info_list = fd.readline().split(',')
to_addr = (info_list[0],int(info_list[1]))
print to_addr
proxy.serve_forever()# 代理服务器监听的地址
except KeyboardInterrupt:
sys.exit(1)
最后,我用 pyinstaller 生成了一个可执行的二进制程序,使用说明都在里边了
