这篇文章主要介绍了如何使用PHP代码实现socks5代理服务器,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
如果要利用多核,就使用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 (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();
感谢你能够认真阅读完这篇文章,希望小编分享的“如何使用PHP代码实现socks5代理服务器”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。