网站推广.NET

网站推广.NET

PHP简单实现socks5代理服务器

来源:互联网

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(&#39;c*&#39;, $data);    if ($data[1] !== 0x05) {      stream_socket_shutdown($this->fd, STREAM_SHUT_RDWR);      echo &#39;协议不正确.&#39;, 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(&#39;c*&#39;, $data);    $addressType = $data[4];    if ($addressType === 0x03) { // domain      $domainLength = unpack(&#39;c&#39;, 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 &#39;请使用远程dns解析.&#39;, 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(&#39;tcp://0.0.0.0:1080&#39;, $errno, $errstr);if ($server === false)  exit($errstr);$pipePool = new Pool(200, Worker::class);$pool = new Pool(50, &#39;ProxyWorker&#39;, [$pipePool]);for( ; ; ) {  $fd = @stream_socket_accept($server, 60);  if ($fd === false)    continue;  $pool->submit(new Client($fd));}

相关推荐:

php使用swoole实时更新客户端数据

Windows 下安装 swoole有哪些步骤?

PHP学习CURL之爬虫实例

socks5代理服务器