

# 問題点

VMware上で動かしているDebian10において、TCP接続クライアントが動作しません。

TCPソケットサーバーは既存のもので、動作確認済みです。  
1400番ポートを使用することにしています。

Windows上で、以下のソースコードは完全に動作しています。

## Debian上での動作

Debian上で、当該ソースコードを実行すると、`s = self.sock.send(msg)`
を実行した時点で、サーバーからRST終了させられてしまいます。（パケットキャプチャで確認）

この原因が分かりません。

## ソースコード

[code]

    import logging
    import ipaddress
    from ipaddress import AddressValueError
    from queue import Queue
    import socket
    from socket import AF_INET, SOCK_STREAM
    
    import threading
    import time
    
    logging.basicConfig(level=logging.INFO,  format=" %(asctime)s - %(levelname)s - %(message)s ")
    
    class SocketClientError(Exception):
        pass
    
    class SocketClient():
        def __init__(self,host,port):
            self.host, self.port = None, None
            self.is_recv_thread = False
            self.recv_queue = Queue()
    
            try:
                ipchk = ipaddress.IPv4Address(host)
    
                if ipchk.is_multicast:
                    msg = "マルチキャストアドレスは使用できません。"
                    logging.exception(msg)
                    raise SocketClientError(msg)
                if ipchk.is_private:
                    pass
                if ipchk.is_global:
                    pass
                if ipchk.is_link_local:
                    pass
    
            except AddressValueError as e:
                raise e
    
            if not isinstance(port,int):
                msg = "portは整数値を指定してください。"
                logging.exception(msg)
                raise SocketClientError(msg)
            else:
                if port < 1:
                    msg = "portは0より上の整数値を指定してください。"
                    logging.exception(msg)
                    raise SocketClientError(msg)
                self.sock = socket.socket(AF_INET,SOCK_STREAM)
                self.sock.settimeout(1)
    
                self.host = host
                self.port = port
    
                logging.info("socket生成")
    
        def connect(self):
            if not all(
                [self.host,self.port]
            ):
                msg = '接続先が正しく定義されていません。host:{},port:{}'.format(self.host,self.port)
                raise SocketClientError(msg)
            try:
                self.sock.connect_ex((self.host,self.port))
                logging.info("socket connect")
            except ConnectionRefusedError as e:
                msg = 'ソケットの接続を拒否された。接続先の指定が間違っているか、サーバーが停止している可能性があります。'
                logging.exception(msg)
                raise SocketClientError(msg)
    
            try:
                recv_thread = threading.Thread(target=recv,args=(self.sock,self.recv_queue))
                recv_thread.start()
                self.is_recv_thread = True
                logging.info("socket receiver start!!")
            except Exception as e:
                logging.exception(e)
                raise SocketClientError(e)
    
        def send(self,msg):
            if any(
                [
                    isinstance(msg, bytes),
                    isinstance(msg, str),
                ]
            ):
                is_bytes = isinstance(msg, bytes)
                if not is_bytes:
                    msg = msg.encode()
    
                s = self.sock.send(msg)
                if s == 0:
                    msg = "送信できていません。socketが破棄されている可能性があります。"
                    logging.exception(msg)
                    raise SocketClientError(msg)
                else:
                    logging.info("socket send :{}".format(msg))
            else:
                msg = '送信データがバイト列、文字列のどちらかではありません。'
                logging.exception(msg)
                raise SocketClientError(msg)
    
    def recv(sock, recv_queue):
        while True:
            try:
                data = sock.recv(1024)
                logging.info("socket recv :{}".format(data))
                if data == b"":
                    continue
                else:
                    recv_queue.put(data.decode())
            except ConnectionResetError:
                break
            except TimeoutError:
                time.sleep(0.5)
                continue
        sock.shutdown(socket.SHUT_RDWR)
        sock.close()
        return
    
    class command_terminal():
        def __init__(self, instScoket):
            self.instScoket = instScoket
            self.recv_queue = instScoket.recv_queue
    
            print('**** test ctr11 tcp socket command terminal ***')
    
            while(True):
                send_cmd = input("command > ")
                send_cmd += "\r"
                logging.info("send:{}".format(send_cmd))
                self.instScoket.send(send_cmd)
    
                time.sleep(0.3)
    
                while not self.recv_queue.empty():
                    recv_data =self.recv_queue.get()
                    logging.info("recv data:{}".format(recv_data))
    
    
    if __name__ == '__main__':
    
        host = '192.168.1.3'
        port = 1400
        instScoket = SocketClient(host,port)
        instScoket.connect()
    
        time.sleep(1)
    
        command_terminal(instScoket)
    
[/code]


CC BY-SA 4.0
2023-08-28T08:03:04.410
96060
2023-08-28T22:55:00.923
2023-08-28T08:34:21.390
3060
32891
question
python python3 socket debian
Debian 10上でのPythonによるTCP接続がRST終了してしまう


> サーバー、クライアントともにVM上で動作しており、loopbackアドレスで通信しています。

>
[code]

>     host = '192.168.1.3'
>     port = 1400
>     instScoket = SocketClient(host,port)
>  
[/code]

`192.168.1.3`はループバックアドレスではありません。ループバックアドレス`127.0.0.1`を使用するか、Firewallルールを見直す必要があるかもしれません。

* * *

一般に、ネットワーク処理には時間がかかるため、ソケットにはブロッキングモードと非ブロッキングモードが存在します。

  * ブロッキングモードは処理が完了するまで待ってから次に進みます。失敗したらエラーが返されます。
  * 非ブロッキングモードは処理が開始できた時点で次に進みます。処理が完了したかどうか、成功したかどうかは別途調べる必要があります。

しかし、質問のコードにはモード設定をする処理がなくどちらのモードを想定しているのか読み取れません。ブロッキングモードであれば次の行に進んだ時点で処理は完了しているわけですから`time.sleep(1)`のような時間調整は必要ありません。かといって非ブロッキングモードでは処理が成功しているとは限りませんので、完了確認が必要ですがそのようなコードも見当たりません。

> connectionは成功しており、sendされたデータも、パケットキャプチャでは確認できています。

と書かれていますが、`instScoket.connect()`は本当に成功しているのでしょうか？
パケットキャプチャレベルで言うと、３ウェイ・ハンドシェイクの`SYN+ACK`は返ってきているのでしょうか？


CC BY-SA 4.0
2023-08-28T22:55:00.923
96066
2023-08-28T22:55:00.923
4236
96060
answer