Python学習【365日チャレンジ!】162日目のマスターU(@Udemy11)です。
物欲を押さえきれず、コストパフォーマンスの高いアジング用ロッドとリールを購入してしまいました。
おまけに【あおむしの釣行記4】のアジングエキスパートの矢野さんが紹介されていた感度抜群で、世界観が変わるというライン【シンカーアジング】まで購入してしまったので、当分物欲は押さえておかないと大変なことになりそうです。
それでは今日もPython学習を始めましょう。
昨日の復習
昨日は、socket通信の基本情報について学習しました。
socketは【プログラムとネットワークをつなげるもの】で、リアルな世界にあるものだと、電話や郵便ポストの役割と一緒でした。
要求する側と提供する側をつなげる役割を持ってる通信を接続するためのもので、TCP/IP自体をソケット通信と呼ぶこともありました。
詳細については、昨日の記事をごらんください。
今日は、socket通信を実際に処理してみましょう。
Pycharmの準備
socket通信を行うには、サーバーとクライアントが必要ですが、Pycharmで2つのPythonファイルを作成してsocket通信を行うことができるので、そのためのコードを書いていきます。
Pycharmで2つのファイルを作成して、左右の画面表示にしてから操作していきます。
画面を分けるには、ファイルタブを右クリックして表示されるメニューから【Split Vertically】を選択し、不必要なタブを閉じます。
同様に下記の【Terminal】をクリックして、ターミナルウインドウを表示したあと、タブを右クリックして【Split Vertically】で画面を分けることができます。
この状態でコードを書いて、ターミナルからPythonを実行します。
サーバー側コード
まずはサーバー側です。
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('127.0.0.1', 50007))
s.listen(1)
while True:
conn, addr = s.accept()
with conn:
data = conn.recv(1024)
if not data:
break
print('data: {}, addr: {}'.format(data, addr))
conn.sendall(b'Recieved:' + data)
最初にsocketパッケージをインポートします。
4行目でwith
ステートメントを使ってsocketを開きますが、アドレスファミリーとソケットタイプを指定します。
第1引数のAF_INET
は、インターネットからのアドレスで、IPv4インターネットプロトコルを使うときに使います。
第2引数のSOCK_STREAM
は、信頼性と順序性を持った双方向のバイトストリームに対応した接続です。
アドレスファミリについては、代表的なものとして、次のようなものがあります。
- AF_INET:IPv4インターネットプロトコル
- AF_INET6:IPv6インターネットプロトコル
- AF_UNIX:ローカル通信用プロトコル
- AF_PACKET:低レベルのパケットインターフェース
ソケットタイプについての代表的なものはこちら。
- SOCK_STREAM:信頼性と順序性を持った双方向のバイトストリームに対応した接続(TCP)
- SOCK_DGRAM:データグラムをサポートする接続(UDP)
データグラム
配送成功・到達時間・到達順序がネットワークサービスによって保証されることがないパケット交換網における基本転送単位
引用元: Wikipedia
アドレスファミリー、ソケットタイプについての詳細は、Python公式ドキュメントを参考にしてください。
では、コードに戻りましょう。
5行目ではs.bind()
でIPアドレスとポートをソケットに紐付けています。
6行目のs.listen()
は、socketが接続を待つ状態にしています。
引数が1
になっていますが、これはシステムが新しい接続を拒否するまでに許可する未受付の接続の数で、0以上の数字を入れます。
7行目以降はWhile
ループを使って、ソケットからの接続を待つ状態にしています。
8行目のs.accept()
は、接続を受け付けて、接続があったときの返り値をconn
とaddr
に代入しています。
9行目以降が接続があったときの処理で、With
ステートメントを使ってdata
に、ソケットから受信した結果のデータconn
をbytesオブジェクトで代入しています。
引数の1024
は、受け取る最大のバッファサイズになります。
11行目から14行目が実際の処理で、受信したdata
が空の場合は、With
ステートメントを抜けて、取得したdata
とaddr
を表示して、クライアントにdata
を返しています。
処理が終了したあとは、4行目のWhile
ステートメントで接続待ちの状態になります。
クライアント側コード
次にクライアント側のコードを書いてみます。
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(('127.0.0.1', 50007))
s.sendall(b'Hello')
data = s.recv(1024)
print(repr(data))
サーバー側と同様、最初にsocketパッケージをインポートします。
4行目もサーバー側のコードと同じです。
5行目は、サーバー側で紐付けられているソケットにconnect
しています。
6行目のs.sendall()
でバイトデータのHello
を送信し、7行目のs.recv(1024)
で受け取ったデータをdata
に代入したあと、最後にdata
の出力可能な文字列を出力しています。
実際の動き
実際にサーバー側とクライアント側でPythonファイルを実行してみた動画を作りました。
それがこちら
非常に短い動画ですが、サーバー側は、実行した時に特に何も反応がなく、接続を待っている状態になります。
その後、クライアント側を実行すると、サーバーが受け取ったデータとアドレスを表示して、クライアントがサーバーから返されたデータを表示します。
一連のやり取りが終了すれば、クライアント側はターミナルに戻りますが、サーバー側は接続を待つ状態になります。
この状態で、再度、クライアント側のPythonファイルを実行すると同じデータのやり取りが行われます。
目に見えていい感じ
プログラミングをしていると、どうしても頭の中でいろいろと組み立てながらコードを書かないといけないので、かなり脳みそを使うのですが、今回のように、サーバー側とクライアント側の処理が目に見えるようにすると非常にわかりやすくて、理解がすすみます。
理解がすすむと楽しくなってくるので、
- 「こうしたらどうなるんだろう?」
- 「あれやりたいからこうしてみよう」
という欲求が湧いてきて、知らない間に時間が過ぎてしまいます。
普段何気なく利用しているWebの処理が少しずつ分かっていくので、これまでより具体的なイメージが掴めるようになってきましたが、まだまだ学習することが多いので、しっかりと気を引き締めて学習を継続していきたいと思います。
それでは、明日もGood Python!