

socketのTCP通信を用いるコードを書いており、同じグローバルIPアドレスの別機器同士（その場合はグローバルIPアドレスではなくローカルIPアドレスをclient.pyで使います）で以下のことを行ったときは成功したのですが、外部のpcを接続させようとしても失敗してしまいます。どうすればいいのでしょうか。

僕のmacOS14.0でserver.pyを、友人のWindows10でclient.pyを、python3.11.5を用いて実行しました。互いのpcのルーターは異なりますし、勿論IPアドレスも異なります。僕のmacOSでは、54321を番号としてポート開放しました（ポート開放は確実に成功しています）。しかし、いざ僕のpcでserver.pyを実行したあとに友人のpcでclient.pyを実行すると、client.pyの方で以下のエラーが吐かれます。

ファイヤーウォールは両pcとも無効になっています。回線もよいはずです。

stack overflowで質問をするのは今回が初めてなので、足りない情報などありましたらお申し付けください。

※追記1  
「ファイヤーウォールは両pcとも無効になっています。」と書きましたが、もう一度確かめてみると、友人のpcで外部のファイヤーウォールソフトが動いていたので無効にしました。が、そのあとコードを実行しても結果は一切変わりませんでした。  
※追記2  
使用しているWiFiルーターは、BUFFALOのWXR-2533DHP2（https://www.buffalo.jp/product/detail/wxr-2533dhp2.html
）です。ポート開放は公式サイト（https://www.buffalo.jp/support/faq/detail/15022.html
）の順序に沿って行いました。

[code]

    Traceback (most recent call last):
      File "<stdin>", line 2, in <module>
    TimeoutError: [WinError 10060] 接続済みの呼び出し先が一定の時間を過ぎても正しく応答しなかったため、接続できませんでした
    。または接続済みのホストが応答しなかったため、確立された接続は失敗しました。
    
[/code]

＜server.py＞

[code]

    import socket
    
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    with server_socket:
        server_socket.bind(('0.0.0.0', 54321))
        server_socket.listen(1)
        
        client_socket, client_address = server_socket.accept()
        
        with client_socket:
            text_binary = client_socket.recv(1024)
            print(text_binary.decode('utf-8'))
    
[/code]

＜client.py＞

[code]

    import socket
    
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    with client_socket:
        client_socket.connect(('server.pyを実行するpcのグローバルIPアドレス', 54321))
        client_socket.send(b'hello')
    
[/code]


CC BY-SA 4.0
2023-10-08T10:06:37.380
96450
2023-10-09T10:49:21.053
2023-10-09T10:49:21.053
60039
60039
question
python python3 windows macos socket
PythonのSocketで、ルーターの異なる外部機器からの通信ができない


事実としては「接続がタイムアウトした」しかないので、これだけでは原因が何か、対策は何かを回答するのは無理です。(ルータの設定やファイヤーウォールの状況など書かれてますが、経験上「自己申告」は事実と異なることがよくあるので裏付けとなる情報がない場合はあまり信用できないのです)

1つずつ確認していく方が早いのですが、それはこのサイトの趣旨ではないので、総論的な切り分け方法を書いときます。

# なるべく制限のない環境で試す

「自宅で」というのは切り分けには最悪な環境で、ルータの設定がどうとかプロバイダ側でNATされてるとかへんなセキュリティが入ってるとか利用者固有の環境も考慮に含めないといけなくなります。なので、グローバルIPアドレスが直接割り振られてる環境でテストしましょう。

クラウドはクラウドでそっちの癖があるので、時間払いができるVPSが一番いいです。

# いろいろな組み合わせを試す

問題があるのはサーバ側かもしれませんしクライアント側かもしれませんし両方かもしれません。

サーバ側\クライアント側 | 本番 | 仮環境  
---|---|---  
本番 | ○or× | ○or×  
仮環境 | ○or× | ○or×  
  
# 別のポート/プログラムも試す

HTTPなど既知で制限がかかってなさそうなポートでも確認しましょう。自作のプログラムとと、既知のサーバソフトウェア(HTTPならIIS/Apache/nginx)の両方で試すとよいです。

クライアント側もtelnet(プログラムの方)とかで接続してみて試してください。

# 結果をまとめる

結果をまとめると、だいたいどこが悪いのか切り分けがつきます。  
例えば、サーバ側をVPSにしたらつながる、なら自宅の環境が何か引っかかってるな、ということになります。(ただこの場合その先に進むのはまた面倒なのですが)


CC BY-SA 4.0
2023-10-09T00:59:29.580
96451
2023-10-09T00:59:29.580
5793
96450
answer


他の回答にある, 進め方・切り分け方 の補足のようなものかもだけど

いきなりアプリ走らせて「動かない・接続できない」では  
どこに問題があるか切り分けできないので, 通常は OSに備わってる機能で試すのがよいでしょう

  1. `ping` による 経路の確認  
パケットが到達可能かどうか調べる比較的有名なコマンド, `ping`でまず確認するのがよいかも

  2. `nc` による TCP 接続

`ping`による確認は, これで失敗するようならそもそも TCP接続できません(普通は)  
(ただし ICMP or ICMP Echo を制限してるネットワークも 無いとはいえないので, 環境による)

失敗するようなら, さらに別のコマンドで調べることになるでしょう

`nc`コマンドは以下のように。  
(ncコマンドが無いようならクライアントは curlなど利用するのも可能)

[code]

    $ # サーバーサイド
    $ nc -l 54321
    
    $ # クライアント
    $ nc [接続先IPアドレス] 54321
    
[/code]

※  
質問に「同じIPアドレスの別機器同士」とあるけれど, 少々意味不明  
同じグローバル IPアドレス内にある, ローカルのプライベートアドレス同士で通信？  
それとも別の意味でしょうか？


CC BY-SA 4.0
2023-10-09T06:22:19.270
96453
2023-10-09T06:22:19.270
43025
96450
answer


>
> 僕のmacOS14.0でserver.pyを、友人のWindows10でclient.pyを、python3.11.5を用いて実行しました。互いのpcのルーターは異なりますし、勿論IPアドレスも異なります。僕のmacOSでは、54321を番号としてポート開放しました（ポート開放は確実に成功しています）。

「友人のWindows10のclient.py」はどこ宛に接続しようとしたのでしょうか？
「僕（質問者さんご自身）のルーター」の持つグローバルIPアドレスですか？ もしそうなら、届く先は「僕のルーター」であって「僕のmacOS」ではありません。

ルーターにはUPnP機能やDMZ機能があり、「僕のルーター」に届いたパケットを「僕のmacOS」に転送することもできますが、その辺りは「僕のルーター」に依存しますし、「ポート開放は確実に成功しています」が局所的に成功しただけで実際には接続できない状態であった可能性が高いです。


CC BY-SA 4.0
2023-10-09T07:14:53.510
96454
2023-10-09T07:14:53.510
4236
96450
answer