Help us understand the problem. What is going on with this article?

python#Socket通信

More than 1 year has passed since last update.

ネット上には情報たくさんありますのでここで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

うん~なんだか行きそうですね。
クライアント側の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

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

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

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

soup01
free access to information is important. 仕事でFA AREAをやって趣味はPythonなど。 楽しいことたくさんやりたい。 知らない世界へ飛び込みたい。 あと、外国人です。
http://soup01.com/ja/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした