Pythonで遠隔サーバとSocket通信でやりとりしてみた。


目的

  • Pythonで遠隔VPSサーバとデータをやりとりする

やっていることの性質上Insecureな部分が多いので、あくまでテスト・趣味を目的としたものです。

環境

  • CentOS 7.8.2003
  • PHP 7.3
  • Python 3.7
  • さくらのVPS(※10周年おめでとうございます!)

サーバ側

サーバを用意します。
私の例ではさくらのVPSを借りました。

環境構築

(注)さくらのVPS利用時の注意点

コントロールパネルからパケットフィルタリング設定を追加してください。
OFFにすることもできますが、セキュリティ上よろしくないので、お勧めしません。

本例では、50000のポート番号を使いたかったので、一時的にOFFにしました。

ポート設定

必要に応じて設定してください。
本例ではさくらのVPSの設定例です。
また、ポート番号もお好みに応じて変更されて下さい。

$ firewall-cmd --zone=public --add-port=50000/tcp --permanent

設定の反映もお忘れなく!

$ firewall-cmd --reload

phpをインストール

本例ではphp7.3をインストールします。

remi

$ yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm

いろいろ余計なものも入ってしまってますが、必要であれば適時ご変更ください。

$ yum -y install --enablerepo=remi,remi-php73 php php-mbstring php-xml php-xmlrpc php-gd php-pdo php-pecl-mcrypt php-mysqlnd php-pecl-mysql

PHP-WebSocketを使ってソケットサーバ構築

本例では外部ライブラリであるPHP-WebSocketを使います。

ここにあるバイナリをApacheディレクトリに落としてください。

$ cd /var/www/html
$ wget https://github.com/nicokaiser/php-websocket/archive/php-websocket.zip
$ unzip php-websocket.zip
$ sudo rm -rf php-websocket.zip

ダウンロードが終わったら、php-websocket/serverにあるserver.phpを編集します。
vimがインストールされてない場合、viを使用するかyum -y install vimでインストールしてください。

$ cd php-websocket/server
$ vim server.php

'<グローバルIPv4アドレス>'50000(ポート)を適時変更・保存してください。

<?php

error_reporting(0);

require(__DIR__ . '/lib/SplClassLoader.php');

$classLoader = new SplClassLoader('WebSocket', __DIR__ . '/lib');
$classLoader->register();

$server = new \WebSocket\Server('<グローバルIPv4アドレス>', 50000);
$server->registerApplication('echo', \WebSocket\Application\EchoApplication::getInstance());
$server->registerApplication('time', \WebSocket\Application\TimeApplication::getInstance());
$server->run();

次に、php-websocket/lib/WebSocket/Connection.phpにあるハンドシェイク関数を書き換えます。
28行目のhandshake関数を下記のように書き換えます。

private function handshake($data)
{
    socket_write($this->socket, $data, strlen($data));
    $this->application->onConnect($this);
    return true;
}

WebSocketサーバを起動

下記のコマンドで起動します。

$ php server.php

このようになれば、サーバ起動完了です。クライアントに移ります。

[root@~]# php server.php 
2020-09-14 14:02:13 [info] Server created

クライアント側(Python)

データを送信するクライアント側のコードです。

  • '<グローバルIPv4アドレス>'を置き換え
  • 50000はポートです
import socket

if __name__ == '__main__':
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.connect(('<グローバルIPv4アドレス>', 50000))
        data = 'Hello From Python Client!'
        sock.send(data.encode())
        print(sock.recv(1024).decode())

叩いてみる

送信したデータがエコーされれば成功です。
かなりゴリ押し気味ですが、とりあえずできました。

[root@myserver]# php server.php 
2020-09-14 15:00:53 [info] Server created
2020-09-14 15:00:55 [info] [client XXX] Connected

おわりに

意外と面倒だった。。
ご覧いただきありがとうございました。