python#Socket通信

ネット上には情報たくさんありますのでここでSocket通信とはなにかを説明しなくてよいだと思います。

https://qiita.com/megadreams14/items/32a3eed4661e55419e1c
http://research.nii.ac.jp/~ichiro/syspro98/socket.html
https://qiita.com/tatsuya4150/items/474b60beed0c04d5d999


PythonではSocketのモジュールがあり、今回はこれを使います。
サンプルコードはサーバー側とクライアント側に分けてます。

## 簡単なメッセージを投げてみよう
まずサーバがずっとリクエストが待って、クライアントがリクエストきたらwelcome to my server!を返しします。

### サーバー側

```
import socket

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((socket.gethostname(),8020))
s.listen(5)

while True:
	clientsocket,address=s.accept()
	print('Connection from {} is established'.format(address))
	clientsocket.send(bytes('welcome to my server!','utf8'))
	clientsocket.close()
```

### クライアント側

```
import socket

#a stream of data is coming, you should define how long of your track.
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((socket.gethostname(),8020))

#buffer
msg=s.recv(1024)
#beacause we are receiving the byte, we need to decode the bytes.
print(msg.decode('utf-8'))
s.close()


```
Terminalからみると…
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/27c26483-c598-cae3-d3db-5904e4d0bc39.png)


うん～なんだか行きそうですね。
クライアント側のmsg=s.recv(1024)の1024ちょっと気になるね。これを(1)にしたらどうになるのかな。

```
import socket

#a stream of data is coming, you should define how long of your track.
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((socket.gethostname(),8020))

#buffer
Entire_msg=''
while True:
	msg=s.recv(1)
	print(msg)
	Entire_msg+=msg.decode('utf-8')
	if len(msg) <=0 :
		break


#beacause we are receiving the byte, we need to decode the bytes.
print(Entire_msg)
s.close()
```
なるほど、msg=s.recv(1)は毎回もらうのデータサイズを決めるってことだね～
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/ede59366-5916-ccd8-d6fc-49a6b7111bd9.png)

## FIX_HEADERをつけてみよう

三菱CPUのMC-Protocolとか色々なHeaderがあるじゃない？それはなになにFrameとかデータのアドレスをどこから取るとか、
何個アドレス取るとか。ここで仮に簡単FIX_HEADERを作ってみますね～

FIX_HEADERの仕様：
長さ：20
MESSAGEの文字列の長さ＋SPACE
例えば、Welcome to the serverなら、21                  Welcome to the serverになります。


```
import socket
import time

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((socket.gethostname(),8020))
s.listen(5)

FIX_HEADER=20

while True:
	
	msg='Welcome to the server'
	le= str(len(msg))
	msg=le+(FIX_HEADER-(len(str(len(msg)))))*' '+msg

	clientsocket,address=s.accept()
	print('Connection from {}'.format(address))
	clientsocket.send(bytes(msg,'utf8'))

```

こっちはクライアント側です：


```
import socket


FIX_HEADER=20

#a stream of data is coming, you should define how long of your track.
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((socket.gethostname(),8020))

while True:
	#buffer

	full_msg=''
	new_msg=True
	while True:
		msg=s.recv(10)
		if new_msg:
			print('new message:{}'.format(msg[:FIX_HEADER]))
			print(msg[:FIX_HEADER])
			msglen=int((msg[:FIX_HEADER]))
			new_msg=False

		full_msg+=msg.decode('utf-8')

		if len(full_msg)-FIX_HEADER == msglen:
			print('All Recv..')
			print(full_msg[FIX_HEADER:])
			new_msg=True
			full_msg=''

	print(full_msg)

```
うん、大丈夫そうですね。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/df799597-0861-ef20-74e5-e6bb22ae2d04.png)


## Python Objectを送ってみよう
ここで使われてるのPythonのPickleモジュールです。サンプルコードは辞書を使うですが、
場合によってJSONでもLISTでもなんでもOKです！

こちはサーバ側です：

```
import socket
import time
import pickle

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((socket.gethostname(),8020))
s.listen(5)

FIX_HEADER=20

while True:
	
	# msg='Welcome to the server'
	d={1:'Hello',2:'I am here'}
	msg=pickle.dumps(d)
	print(msg)
	le= str(len(msg))

	header=(((le+(FIX_HEADER-(len(str(len(msg)))))*' ')))

	header2=bytes(header.encode())
	msg=header2+msg
	

	clientsocket,address=s.accept()
	print('Connection from {} is established on {}'.format(address,time.time()))
	
	clientsocket.send(msg)

```
クライアント側：

```
import socket
import pickle

FIX_HEADER=20

#a stream of data is coming, you should define how long of your track.
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((socket.gethostname(),8020))

while True:
	#buffer

	full_msg=b''
	new_msg=True
	while True:
		msg=s.recv(10)
		if new_msg:
			print('new message:{}'.format(msg[:FIX_HEADER]))
			print('*')

			msglen=int((msg[:FIX_HEADER]))
			print(msglen)
			new_msg=False

		full_msg+=msg
		print(full_msg)

		if len(full_msg)-FIX_HEADER == msglen:
			print('All Recv..')
			print(full_msg[FIX_HEADER:])

			d=pickle.loads(full_msg[FIX_HEADER:])

			new_msg=True
			
			print('*')
			print(d)

```

うん、大丈夫ですね！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/ec61c714-a659-535f-2f7d-131190463a4a.png)

以上になりますが、今回ここでSocket一回自分の手でやってみたらPLCとかでなんでここでこんな設定にならないと
だめなんだ？とか少しわかると気がします。