
開きたいポートを転送した後、このポートに接続したりデータを取得したりできないようです。私が書いたPHP CLIソフトウェアは、ポートをアクティブにリッスンしています。ウブントゥ 14.04コードの一部を以下に示します。ポートは AF_INET として開かれ、スクリプトは各行でエラーをスローせず、/etc/protocols では tcp が 'tcp 6 TCP' として定義されています。
// I have tried $host=gethostbyname(gethostname());$port=8399 (host is 127.0.1.1)
// as well as $host = '0.0.0.0'; $port = 8399; and other addresses
$this->wsRead[0] = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)
socket_set_option($this->wsRead[0], SOL_SOCKET, SO_REUSEADDR, 1)
socket_bind($this->wsRead[0], $host, $port)
socket_listen($this->wsRead[0], 10)
while (isset($this->wsRead[0])) { /* Handshake/Process data, etc. */ }
ポートは転送され、私のiptablesは空ですただし、ポートの許可ルールを具体的に追加しようとしました。スクリプトをスーパーユーザーとして実行してみました。サーバーがリッスンしているとき、netstat -tuln はこの行をリストします (ポート 8399)。また、apache もリストされているのに気づきました。これは正常に動作し、外部ポート チェック Web サイトから開いているポートとして表示されます (ポート 8301)。
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:8399 0.0.0.0:* LISTEN
tcp6 0 0 :::8301 :::* LISTEN
tcp6 0 0 :::80 :::* LISTEN
nmap を使用すると、ポートも開いていることが示されます。別のポートも試しました。クライアント側の接続スクリプトは、Windows で PHP CLI を実行するときに接続できる JavaScript Websocket スクリプトです。スクリプトは長すぎてここには含められません。また、外部ネットワークからは接続できません。JS スクリプトと PHP スクリプトの両方をローカル アドレス 127.0.0.1 または 192.168.0.### に設定すると、LAN 外部のデバイスからは接続できませんが、機能します。
// The JS is basically this, plus some connection events to alert success/fail.
// This external connection request will always time out
Server = new WebSocket('ws://68.215.154.129:8399');
iptables 以外に、バイパスしていない Linux のファイアウォールが不足しているのでしょうか? Apache はポートを正しく開いており、PC 上の他のソフトウェアも開いていますが、外部使用のためにポートを完全に開くために必要な手順がスクリプトに欠けているようです。
tl,dr; JavaScript クライアントを使用して外部 IP アドレスで PHP サーバーに接続しますが、Windows では動作しますが、Ubuntu では動作しません。ポート転送、リスニング、iptables によってブロックされていない、何が残っているでしょうか?
答え1
概念的にもコード的にも何かが欠けています。接続を待機する PHP コードがありますが、使用する前に接続を受け入れる必要があります。
$ns = socket_accept($this->wsRead[0]);
$some_string = socket_read($ns, 128);
呼び出しはsocket_accept()
ブロックされます。何らかのクライアント プログラムが現在接続を待機しているプログラムに接続するまで戻りません。
socket_accept()
を呼び出すと、リモート プログラムとの通信に使用する実際のソケットが返されます。 は実際には必要なものではないと思いますので、isset()
調べる必要がありますsocket_select()
。リモートとの通信が完了したら、 を呼び出しsocket_close($ns)
、 に戻ってループしsocket_accept($this->wsRead[0])
、別のリモート プログラムがプログラムに接続するのを待ちます。
PHP プログラムが接続の処理を完了したら、socket_close($this->wsRead[0])
ソケットを閉じるために を呼び出す必要があります。これは基本的に、指定したポートの着信 TCP SYN パケットのリッスンを終了するように OS カーネルに指示します。
答え2
結局、問題は複数の原因から生じており、主にモデム/ルーターから生じていました。私はモトローラ SB6580は最近ファームウェアのアップデートが行われましたが、10 日間再起動されていないため、動作がかなり遅くなり、あまり変更を加えたくない状態になっています。
のファームウェアアップデートによりポート転送ページが変更されました外部リモート ホスト アドレス セクション (デフォルトは 0.0.0.0) を含めることは問題ありませんが、他の操作によって、私が設定した既存のポート転送ルールが破られました。
転送するポートの範囲を使用していましたが、動作していませんでした。この範囲を 8399 - 8399 に変更すると、再び動作するようになりました。再起動しても、モデムの速度が上がる以外は影響はなく、プロトコルを両方から TCP に変更しても影響はありませんでした。
IP Addr|Start Port|End Port|Remote Host Addr|Start Port|End Port|Protocol|Enabled
192.168.0.101|8340| 8399| 0.0.0.0| 8340| 8399| Both|Checked
192.168.0.101|8399| 8399| 0.0.0.0| 8399| 8399| TCP|Checked
また、LinuxでPHPのコマンドgethostbyname(gethostname())を使用すると、返されるアドレスは/etc/hostsファイルの2番目のエントリである127.0.1.1のローカルアドレスであり、ソケットのバインドには機能しません。$_SERVER['REMOTE_ADDR']も警告を返します。ホストを検索できません。これを手動でホーム(サブネット?)アドレス(私のは192.168.0.101)またはIPv4ワイルドカード0.0.0.0に変更します。ソケット リスナーは正しくバインドされ、外部接続を受け入れます。
ルーターの経験と Linux の経験不足により、Linux のトラブルシューティングを間違った方向に進めてしまいました。Windows 7 でも動作しないことに気付き、上記の 2 つの変更を加えたところ、すべて正常に動作するようになりました。