100多行PHP代码实现socks5代理服务器,这次是使用swoole纯异步来写,使用状态机来处理数据。目前用它访问开源中国木有压力,但访问网易新闻就压力山大。我发现我用别的语言写得代理,访问网易新闻都压力大。嘎嘎,学艺不精。
对swoole理解不深,不知道怎么处理socket shutdown只关闭读/写这样,还有就是连接超时,读写超时这种怎么处理。在网上看到作者说要用定时器,感觉好麻烦,所以,这次的代理,虽然个人用,一般不会有什么问题,但离产品级的代理,还有段路要走。
如果要利用多核,就使用process模式,设置worker个数为cpu数量即可。
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
<?php class Client { public $data = '' ; public $remote = null; public $status = 0; } class Server { public $clients = []; { $server = new swoole_server( '0.0.0.0' , 8388, SWOOLE_BASE, SWOOLE_SOCK_TCP); $server ->set([ 'max_conn' => 1000, 'daemonize' => 1, 'reactor_num' => 1, 'worker_num' => 1, 'dispatch_mode' => 2, 'buffer_output_size' => 128 * 1024 * 1024, 'open_cpu_affinity' => 1, 'open_tcp_nodelay' => 1, 'log_file' => 'socks5_server.log' , ]); $server ->on( 'connect' , [ $this , 'onConnect' ]); $server ->on( 'receive' , [ $this , 'onReceive' ]); $server ->on( 'close' , [ $this , 'onClose' ]); $server ->start(); } public function onConnect( $server , $fd , $fromID ) { $this ->clients[ $fd ] = new Client(); } public function onReceive( $server , $fd , $fromID , $data ) { ( $this ->clients[ $fd ])->data .= $data ; $this ->parse( $server , $fd ); } public function onClose( $server , $fd , $fromID ) { $client = $this ->clients[ $fd ]; $client ->connected = false; } { $client = $this ->clients[ $fd ]; switch ( $client ->status) { case 0: { if ( strlen ( $client ->data) >= 2) { $request = unpack( 'c*' , substr ( $client ->data, 0, 2)); if ( $request [1] !== 0x05) { echo '协议不正确:' . $request [1], PHP_EOL; $server ->close( $fd ); break ; } $nmethods = $request [2]; if ( strlen ( $client ->data) >= 2 + $nmethods ) { $client ->data = substr ( $client ->data, 2 + $nmethods ); $server ->send( $fd , "x05x00" ); $client ->status = 1; } } } case 1: { if ( strlen ( $client ->data) < 5) break ; $request = unpack( 'c*' , $client ->data); $aType = $request [4]; if ( $aType === 0x03) { // domain $domainLen = $request [5]; if ( strlen ( $client ->data) < 5 + $domainLen + 2) { break ; } $domain = substr ( $client ->data, 5, $domainLen ); $port = unpack( 'n' , substr ( $client ->data, 5 + $domainLen , 2))[1]; $client ->data = substr ( $client ->data, 5 + $domainLen + 2); } else if ( $aType === 0x01) { // ipv4 $domain = long2ip(unpack( 'N' , substr ( $client ->data, 4, 4))[1]); $port = unpack( 'n' , substr ( $client ->data, 8, 2))[1]; $client ->data = substr ( $client ->data, 10); } else { echo '不支持的atype:' . $aType , PHP_EOL; $server ->close( $fd ); break ; } $remote = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC); $remote ->on( 'connect' , function ( $cli ) use ( $client , $server , $fd , $remote ) { $server ->send( $fd , "x05x00x00x01x00x00x00x00x00x00" ); $client ->status = 2; $client ->remote = $remote ; }); $remote ->on( "error" , function (swoole_client $cli ) use ( $server , $fd ) { //$server->send($fd, ""); // todo 连接不上remote echo 'connect to remote error.' , PHP_EOL; $server ->close( $fd ); }); $remote ->on( 'receive' , function ( $cli , $data ) use ( $server , $fd , $client ) { if (! $client ->connected) { echo 'connection has been closed.' , PHP_EOL; return ; } $server ->send( $fd , $data ); }); $remote ->on( 'close' , function ( $cli ) use ( $server , $fd , $client ) { $client ->remote = null; }); if ( $aType === 0x03) { swoole_async_dns_lookup( $domain , function ( $host , $ip ) use ( $remote , $port , $server , $fd ) { //todo 当host为空时的处理。貌似不存在的域名都解析成了本机的外网ip,奇怪 if ( empty ( $ip ) || empty ( $host )) { echo "host:{$host}, ip:{$ip}n" ; $server ->close( $fd ); return ; } $remote ->connect( $ip , $port ); }); } else { $remote ->connect( $domain , $port ); } } case 2: { if ( strlen ( $client ->data) === 0) { break ; } if ( $client ->remote === null) { echo 'remote connection has been closed.' , PHP_EOL; break ; } $sendByteCount = $client ->remote->send( $client ->data); if ( $sendByteCount === false || $sendByteCount < strlen ( $client ->data)) { echo 'data length:' , strlen ( $client ->data), ' send byte count:' , $sendByteCount , PHP_EOL; echo $client ->data, PHP_EOL; $server ->close( $fd ); } $client ->data = '' ; } } } } ( new Server())->start(); |
© 版权声明
本文刊载的所有内容,包括文字、图片、音频、视频、软件、程序、以及网页版式设计等部门来源于互联网,版权均归原作者所有!本网站提供的内容服务于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。
联系信息:邮箱aoxolcom@163.com或见网站底部。
联系信息:邮箱aoxolcom@163.com或见网站底部。
THE END
请登录后发表评论
注册
社交帐号登录