今さらpythonでsocketserverを使ってソケット通信する

# 目的
以下を参考に、今さら感がありつつもpythonでTCP/UDPのソケット通信した際の備忘録です

> [socketserver --- ネットワークサーバのフレームワーク](https://docs.python.org/ja/3/library/socketserver.html)

### ソケット通信について

> ソケット インターネットはTCP/IPと呼ぶ通信プロトコルを利用しますが、そのTCP/IPをプログラムから利用するには、プログラムの世界とTCP/IPの世界を結ぶ特別な出入り口が必要となります。 その出入り口となるのがソケット(Socket)であり、TCP/IPのプログラミング上の大きな特徴となっています。
> 引用元: [http://research.nii.ac.jp/~ichiro/syspro98/socket.html](http://research.nii.ac.jp/~ichiro/syspro98/socket.html)

### TCPのソケット通信

client側がserver側に送ったアルファベットを、server側が大文字にしてclientへ返す

```python:receiver.py
import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        self.data = self.request.recv(1024).strip()
        print("{} wrote:".format(self.client_address[0]))
        print(self.data)
        self.request.sendall(self.data.upper())

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999

    with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
        server.serve_forever()
```

```python:sender.py
import socket
import sys

HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    sock.connect((HOST, PORT))
    sock.sendall(bytes(data + "\n", "utf-8"))
    received = str(sock.recv(1024), "utf-8")

print("Sent:     {}".format(data))
print("Received: {}".format(received))
```

実行する

```
$ python receive.py
```

```
$ python sender.py "hello world"
Sent:     hello world
Received: HELLO WORLD
```

### UDPのソケット通信

UDPはTCPと違い、connectionがなく、データも送りっぱなし

```python:receiver.py
import socketserver

class MyUDPHandler(socketserver.BaseRequestHandler):

    def handle(self):
        data = self.request[0].strip()
        socket = self.request[1]
        print("{} wrote:".format(self.client_address[0]))
        print(data)
        socket.sendto(data.upper(), self.client_address)

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    with socketserver.UDPServer((HOST, PORT), MyUDPHandler) as server:
        server.serve_forever()
```

```python:sender.py
import socketserver

class MyUDPHandler(socketserver.BaseRequestHandler):

    def handle(self):
        data = self.request[0].strip()
        socket = self.request[1]
        print("{} wrote:".format(self.client_address[0]))
        print(data)
        socket.sendto(data.upper(), self.client_address)

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    with socketserver.UDPServer((HOST, PORT), MyUDPHandler) as server:
        server.serve_forever()
```

実行する

```
$ python receive_udp.py
```

```
$ python sender_udp.py "hello world. udp."
Sent:     hello world. udp.
Received: HELLO WORLD. UDP.
```

# 備考

通信データが大きい場合に実行時間や欠損データの扱いの面で差が出ると思うが、お試しなので省略
UDPはTCPと違いについて詳しくは以下
> [ソケット通信](http://www.ne.jp/asahi/hishidama/home/tech/socket/)

# 参考
[socketserver --- ネットワークサーバのフレームワーク](https://docs.python.org/ja/3/library/socketserver.html)
[Pythonによる通信処理](https://qiita.com/nadechin/items/28fc8970d93dbf16e81b)
[cpython/Lib/socketserver.py](https://github.com/python/cpython/blob/3.8/Lib/socketserver.py)
[知ったかぶりをしていたソケット通信の基礎を改めて学んでみる](https://qiita.com/megadreams14/items/32a3eed4661e55419e1c)
[まつもと直伝　プログラミングのオキテ 第16回　ネットワーク・プログラミング（ソケット編）](https://xtech.nikkei.com/it/article/COLUMN/20071031/285990/?rt=nocnt)
[ソケット通信](http://www.ne.jp/asahi/hishidama/home/tech/socket/)