100多行PHP代码实现socks5代理服务器[2]
发布:smiling 来源: PHP粉丝网 添加日期:2021-08-01 14:24:42 浏览: 评论:0
100多行PHP代码实现socks5代理服务器,这次是使用swoole纯异步来写,使用状态机来处理数据。目前用它访问开源中国木有压力,但访问网易新闻就压力山大,我发现我用别的语言写得代理,访问网易新闻都压力大,嘎嘎,学艺不精。
对swoole理解不深,不知道怎么处理socket shutdown只关闭读/写这样,还有就是连接超时,读写超时这种怎么处理。在网上看到作者说要用定时器,感觉好麻烦,所以,这次的代理,虽然个人用,一般不会有什么问题,但离产品级的代理,还有段路要走。
如果要利用多核,就使用process模式,设置worker个数为cpu数量即可。
- <?php
- class Client
- {
- public $connected = true;
- public $data = '';
- public $remote = null;
- public $status = 0;
- }
- class Server
- {
- public $clients = [];
- public function start()
- {
- $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;
- }
- private function parse($server, $fd)
- {
- $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, "\x05\x00");
- $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, "\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00");
- $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 (emptyempty($ip) || emptyempty($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();
Tags: socks5代理服务器
推荐文章
热门文章
最新评论文章
- 写给考虑创业的年轻程序员(10)
- PHP新手上路(一)(7)
- 惹恼程序员的十件事(5)
- PHP邮件发送例子,已测试成功(5)
- 致初学者:PHP比ASP优秀的七个理由(4)
- PHP会被淘汰吗?(4)
- PHP新手上路(四)(4)
- 如何去学习PHP?(2)
- 简单入门级php分页代码(2)
- php中邮箱email 电话等格式的验证(2)