LoginSignup
0
0

More than 3 years have passed since last update.

Socketモジュールを使ったTCP通信 - Python3

Last updated at Posted at 2020-11-09

前回の記事と一緒にご覧ください。Python3のソケットモジュールとソケット通信の流れ
python3のsocketモジュールを使った、TCP通信の簡単な例

環境

Python: 3.6
必要とするモジュール: colorama

実行結果とソースコード

サーバー側(ソケット通信二回分)

server_side_img.jpg

import socket
from colored_print import print_msg


SERVER_ADDRESS = ('192.168.1.200', 8000)

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(SERVER_ADDRESS)

sock.listen(0)

for i in range(2):
    try:
        conn_sock, client_address = sock.accept()
        print_msg('ac', 'The connection accepted.')
        print_msg('i', '{}:{} --------> {}:{}'
                  .format(client_address[0], client_address[1],
                          SERVER_ADDRESS[0], SERVER_ADDRESS[1]))

        # Receiving process
        amount_received = 0
        MSGLEN = int(conn_sock.recv(4))
        print_msg('i', 'MSGLEN: {}'.format(MSGLEN))

        while amount_received < MSGLEN:
            data = conn_sock.recv(min(MSGLEN - amount_received, 32))
            print_msg('i', 'received: {}'.format(data))
            amount_received += len(data)
            if not data:
                raise RuntimeError('The connected socket broken.')

            # Sending process
            conn_sock.send(data)
            print_msg('i', 'send: {}'.format(data))
    finally:
        conn_sock.close()
        print_msg('cl', 'The connection closed.')

クライアント側

client_side_img.jpg

import socket
from colored_print import print_msg


SERVER_ADDRESS = ('192.168.1.200', 8000)
MSG = 'Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do.'
MSGLEN = len(MSG)

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
    sock.connect(SERVER_ADDRESS)
    print_msg('cn', 'The connection accepted')

    print_msg('i', 'MSGLEN: {}'.format(MSGLEN))
    sock.send(bytes(str(MSGLEN), 'utf-8').zfill(4))

    # Sending process
    sock.send(bytes(MSG, 'utf-8'))

    # Receiving process
    chunks = []
    amount_received = 0
    while amount_received < MSGLEN:
        data = sock.recv(min(MSGLEN - amount_received, 32))
        print_msg('i', 'received: {}'.format(data))
        amount_received += len(data)
        if not data:
            raise RuntimeError('The connected socket broken.')
        chunks.append(data)
finally:
    sock.close()
    print_msg('cl', 'The connection closed.')

result = '''
Result: [
    MSGLEN: {},
    Send: {},
    Received: {}
]
'''.format(MSGLEN, MSG, chunks)

print_msg('i', result)

解説

recvのループのブレイクは、

  1. b''が来たらブレイクする。
  2. メッセージの長さがわかるなら受信分の長さがメッセージの長さと等しくなったらブレイクする。

のに種類があるが、1.の問題点は通信の途中で通信が壊れたときにもb''が渡されるということ。そこで今回は新しくはじめに送る4バイトはメッセージの長さであると言うルールを作った。

サーバー側

[ACCEPT]から[CLOSE]までが一つのソケット通信。

クライアントから来たメッセージを受け取ったらすぐに送り返す。

クライアント側

[CONNECT]から[CLOSE]までが一つのソケット通信。

colored_print

下のコードを同じディレクトリに配置してください。

colored_print.py
from colorama import Fore, Style


def print_msg(header, msg):
    '''header are i that is INFO or e that is ERROR'''

    if header == 'i':
        print(Fore.GREEN + '[INFO]',
              Style.RESET_ALL + msg)
    elif header == 'e':
        print(Fore.RED + '[ERROR]',
              Style.RESET_ALL + msg)
    elif header == 'ac':
        print(Fore.BLUE + '[ACCEPT]',
              Style.RESET_ALL + msg)
    elif header == 'cn':
        print(Fore.BLUE + '[CONNECT]',
              Style.RESET_ALL + msg)
    elif header == 'cl':
        print(Fore.BLUE + '[CLOSE]',
              Style.RESET_ALL + msg)
    else:
        print(Fore.RED + 'ERROR: header is an invalid value.'
              + Style.RESET_ALL)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0