首页PHP文章详情

nginx+swoole webscoket如何获取真实的客户端IP

By liajitu / Aug 8, 2019 阅读 0 评论 0 发表于 PHP 字数:1930 阅读时间:20秒

websocketswoole客户端IP

摘要:实际开发游戏项目中,需要获取客户端IP,系统基于swoole搭建的webscoket服务,那么如何获取了?本文通过2种方式来实现

方式一 :通过 swoole 的request 对象获取客户端IP

场景: 客户端直接远程使用IP+端口访问webscoket服务。

例如: ws://192.168.10.22:9502 

关键核心代码如下:

$server->on('message', function($server, $frame) {
    $res =  $server->getClientInfo($frame->fd);
    $ip = $res[‘remote_ip’];
}

$res 具体数据格式:

array(11) {
  ["websocket_status"]=>int(3)
  ["server_port"]=>int(9502)
  ["server_fd"]=>int(9)
  ["socket_fd"]=>int(23)
  ["socket_type"]=>int(1)
  ["remote_port"]=>int(50758)
  ["remote_ip"]=>string(9) "127.0.0.1"
  ["reactor_id"]=>int(3)
  ["connect_time"]=>int(1565747287)
  ["last_time"]=>int(1565747287)
  ["close_errno"]=>int(0)
}

提示: 远程开放socket端口不安全,不建议此方式

方式二: 通过 nginx 反向代理到 webscoket  获取客户端IP

首先配置nginx反向代理,配置关键代码如下:

location /websocket {
   proxy_redirect off;
   proxy_pass                 #websocket
   proxy_http_version 1.1;
   proxy_set_header Upgrade $http_upgrade;
   proxy_set_header Connection 'upgrade';
   proxy_set_header Host $http_host;
   proxy_set_header X-Forwarded-For $remote_addr;   #配置IP
}

假设我们这里配置的域名是:www.lakeui.com 

场景: 客户端通过域名访问webscoket服务。

例如: ws://www.lakeui.com/webscoket

由于所有客户端都是通过nginx代理到websocket,所以websocket再通过方法一获取的ip都是127.0.0.1 ,这里的关键就在nginx的反向代理配置:

proxy_set_header X-Forwarded-For $remote_addr;

表示将客户端IP通过头信息传递给websocket,webscoket可以通过头信息获取客户端IP,关键核心代码如下:

$server->on('open', function($server, $req) {    
    $ip  = $req->header['x-forwarded-for']; 
});

本以为可以结束了,可实际swoole只有在open回调方法中才能获取request对象,可业务一般在message回调中处理,ip又如何获取和传递了?

查询了swoole相关文档,没有找到相应的获取方法于是只有想办法将ip传递。关键代码如下:

$ips = [];   //定义一个全局ip存放数组
$server->on('open', function($server, $req) {  
    global $ips;
    $ips[$req->fd] = $req->header['x-forwarded-for'];  //将客户端标示与IP关联存入全局数组 
});

$server->on('message', function($server, $frame) {
    global $ips;   
    $ip = $ips[$frame->fd];   //获取客户端IP
});

//注意一定要释放ip,否则会导致内存爆掉
$server->on('close', function($server, $fd) {
    global $ips;
    unset($ips[$fd]);  //客户端断开时清除ip关联
});

以上方式是目前我发现的解决办法,如果各位大神又更好的解决方法,可以留言或者联系我,一起共同学习!


手机扫码阅读,舒服~

⌘ + Return 发表
最新 最早 全部评论0 条评论