100行代码能(简单)实现个啥好玩的?本文以实例展示了100行php代码简单实现socks5代理服务器模块,希望对大家有所帮助。
当然,由于php(不算swoole扩展)本身不擅长做网络服务端编程,所以这个代理,只是个玩具,离日常使用有点距离。
写的过程中发现php多线程还是难的。比如我开始想每个连接新建一个线程。但这个线程得保存起来(比如保存到数组) 要放到$clients这个数组里,不然,你试试(curl -l一个要301的地址)就知道出现什么情况了。
那,以下就是使用线程池来实现的代理,按道理讲,退出时池要shutdown(),监听socket也要shutdown的,但百行代码,就不勉强了,随着ctrl + c,就让操作系统来回收资源吧。
php不擅长网络编程体现在哪里呢?首先我用的是stream_socket_xxx相关的函数,为啥不用socket扩展呢?因为socket扩展有问题。而stream_set_timeout对stream_socket_recvfrom这些高级操作,不起作用。 而这些,在写代理时都需要考虑的。比如连接远程目标服务器时,没有超时控制,很容易就线程池跑满了。
测试的话,使用curl即可,对了,目前只支持远程dns解析,为啥呢?因为这个玩具后期可是要实现禾斗学上网的哟: curl --socks5-hostname 127.0.0.1:1080 http://ip.cn
class pipe extends threaded
{
private $client;
private $remote;
public function __construct($client, $remote)
{
$this->client = $client;
$this->remote = $remote;
}
public function run()
{
for ( ; ; ) {
$data = stream_socket_recvfrom($this->client, 4096);
if ($data === false || strlen($data) === 0) {
break;
}
$sendbytes = stream_socket_sendto($this->remote, $data);
if ($sendbytes <= 0) {
break;
}
}
stream_socket_shutdown($this->client, stream_shut_rd);
stream_socket_shutdown($this->remote, stream_shut_wr);
}
}
class client extends threaded
{
public $fd;
public function __construct($fd)
{
$this->fd = $fd;
}
public function run()
{
$data = stream_socket_recvfrom($this->fd, 2);
$data = unpack('c*', $data);
if ($data[1] !== 0x05) {
stream_socket_shutdown($this->fd, stream_shut_rdwr);
echo '协议不正确.', php_eol;
return;
}
$nmethods = $data[2];
$data = stream_socket_recvfrom($this->fd, $nmethods);
stream_socket_sendto($this->fd, "\x05\x00");
$data = stream_socket_recvfrom($this->fd, 4);
$data = unpack('c*', $data);
$addresstype = $data[4];
if ($addresstype === 0x03) { // domain
$domainlength = unpack('c', stream_socket_recvfrom($this->fd, 1))[1];
$data = stream_socket_recvfrom($this->fd, $domainlength + 2);
$domain = substr($data, 0, $domainlength);
$port = unpack("n", substr($data, -2))[1];
} else {
stream_socket_shutdown($this->fd, stream_shut_rdwr);
echo '请使用远程dns解析.', php_eol;
}
stream_socket_sendto($this->fd, "\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00");
echo "{$domain}:{$port}", php_eol;
$remote = stream_socket_client("tcp://{$domain}:{$port}");
if ($remote === false) {
stream_socket_shutdown($this->fd, stream_shut_rdwr);
return;
}
$pool = $this->worker->pipepool;
$pipe1 = new pipe($remote, $this->fd);
$pipe2 = new pipe($this->fd, $remote);
$pool->submit($pipe1);
$pool->submit($pipe2);
}
}
class proxyworker extends worker
{
public $pipepool;
public function __construct($pipepool)
{
$this->pipepool = $pipepool;
}
}
$server = stream_socket_server('tcp://0.0.0.0:1080', $errno, $errstr);
if ($server === false)
exit($errstr);
$pipepool = new pool(200, worker::class);
$pool = new pool(50, 'proxyworker', [$pipepool]);
for( ; ; ) {
$fd = @stream_socket_accept($server, 60);
if ($fd === false)
continue;
$pool->submit(new client($fd));
}
相关推荐:
php使用swoole实时更新客户端数据
windows 下安装 swoole有哪些步骤?
php学习curl之爬虫实例
以上就是php简单实现socks5代理服务器的详细内容。