Pythonによる通信処理

*Python3系の分を追記しました

Pythonによる通信処理
この記事は [慶應義塾大学SFC村井&徳田研 Advent Calendar 2015](http://www.adventar.org/calendars/1053) の21日目の記事です。
#1. はじめに

　夏まで「UNIXコマンドってなんやねん」レベルで、ロクに実装もせずに研究意義とかサービスについて語っちゃう自分に嫌気がさして秋学期からPCを触り始めました。
それからSwift,Pythonを触り始めて今はPythonを書いてます。

　つまるところプログラミング初心者です。今回はPythonでのソケット通信について書きます。




##今回の内容

 PythonだけでTCPサーバーを立ててTCPクライアントとソケット通信する。
 

#2. 環境

 * クライアント
  * OS X  --version 10.10.5
  * Python                --version 2.7.10
 * サーバー
  * CentOS        --version 6.5
  * Python                --version 2.7.10



#3.ソースコード本文と手順（コメントアウト参照）

python2系と3系ではデータ型の扱いが異なるところがあるため、それの修正を追記。（あとprint()とinput()も）

 基本的にsocketライブラリを用いて順を追っていきます。
 まずはTCPのクライアントを作成してみます。


```py:client.py（Python2系）
# -*- coding:utf-8 -*-
import socket

host = "xxx.xxx.xxx.xxx" #お使いのサーバーのホスト名を入れます
port = xxxx #適当なPORTを指定してあげます

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #オブジェクトの作成をします

client.connect((host, port)) #これでサーバーに接続します

client.send("from nadechin") #適当なデータを送信します（届く側にわかるように）

response = client.recv(4096) #レシーブは適当な2の累乗にします（大きすぎるとダメ）

print response
```

```py:client.py（Python3系）
# -*- coding:utf-8 -*-
import socket

host = "xxx.xxx.xxx.xxx" #お使いのサーバーのホスト名を入れます
port = xxxx #適当なPORTを指定してあげます

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #オブジェクトの作成をします

client.connect((host, port)) #これでサーバーに接続します

massage = "from nadechin"

client.send(massage.encode('utf-8')) #適当なデータを送信します（届く側にわかるように）

response = client.recv(4096) #レシーブは適当な2の累乗にします（大きすぎるとダメ）

print(response)
```
　Pythonを使用したサーバーやクライアントの基盤となるもので、これを膨らませることで幅広く応用を効かせることが可能です。
UDPのクライアントもこれとほぼ同じように作成することが可能です。（UDP通信の場合はconnect()を呼ぶ必要がない）

　次にTCPのサーバーを作成してみます。
当然のことですがこれも先ほどのTCPのクライアントの形と同じように書きます。

```py:server.py（Python2系）
# -*- coding:utf-8 -*-
import socket

host = "xxx.xxx.xxx.xxx" #お使いのサーバーのホスト名を入れます
port = xxxx #クライアントで設定したPORTと同じもの指定してあげます

serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serversock.bind((host,port)) #IPとPORTを指定してバインドします
serversock.listen(10) #接続の待ち受けをします（キューの最大数を指定）

print 'Waiting for connections...'
clientsock, client_address = serversock.accept() #接続されればデータを格納

while True:
    rcvmsg = clientsock.recv(1024)
    print 'Received -> %s' % (rcvmsg)
    if rcvmsg == '':
      break
    print 'Type message...'
    s_msg = raw_input()
    if s_msg == '':
      break
    print 'Wait...'

    clientsock.sendall(s_msg) #メッセージを返します
clientsock.close()
```

```py:server.py（Python3系）
# -*- coding:utf-8 -*-
import socket

host = "xxx.xxx.xxx.xxx" #お使いのサーバーのホスト名を入れます
port = xxxx #クライアントで設定したPORTと同じもの指定してあげます

serversock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serversock.bind((host,port)) #IPとPORTを指定してバインドします
serversock.listen(10) #接続の待ち受けをします（キューの最大数を指定）

print('Waiting for connections...')
clientsock, client_address = serversock.accept() #接続されればデータを格納

while True:
    rcvmsg = clientsock.recv(1024)
    print('Received -> %s' % (rcvmsg))
    if rcvmsg == '':
      break
    print('Type message...')
    s_msg = input().replace('b', '').encode('utf-8')
    if s_msg == '':
      break
    print('Wait...')

    clientsock.sendall(s_msg) #メッセージを返します
clientsock.close()
```

#4. 実際に動かしてみる
1

```:サーバー側（CentOS）
$ python server.py
Waiting for connections...
```

2

```:クライアント側（MacBook）
$ python client.py 
```

3

```:サーバー側（CentOS）
$ python server.py
Waiting for connections...
Received -> from nadechin
Type message...
Hello World!
```

4


```:クライアント側（MacBook）
$ python client.py 
Hello World!
```

5

```:サーバー側（CentOS）
$ python server.py
Waiting for connections...
Received -> from nadechin
Type message...
Hello World!
Wait...
Received -> 
```


こんな感じでちょっとしたチャットをすることができます。
やり方を変えれば無限にやり取りができたり、メッセージのacceptを無視するようにすれば発言した後でも発言権は残るようにすることが可能です。

#5. おわりに
　こんな雑魚い感じの発表になりましたが、こういった場に書き込む機会を与えてくださってありがとうございます。
今後はC言語を少しづつ学んでネットワークの理解を深めたいです。

#6. 追記
C言語でのソケットプログラミングをして実際にできることを確認しました。
最近は色々つまみ食いばかりでしたが、Honeypotやシステムプログラミングに興味を持ってやり始めているので各々の成果が出ればまた書きます。

#参考文献

Justin Seitz （2014）『サイバーセキュリティプログラミング』青木 一史、新井 悠、一瀬 小夜、岩村 誠、川古谷 裕平、星澤 裕二