LoginSignup
3
1

More than 3 years have passed since last update.

pythonで簡単な echo サーバーを作りましょう

Last updated at Posted at 2021-04-22

概要

Echo server というのはサーバー界のhello worldだと言っても過言でもありません。サーバーサイドの入門に一番相応しい練習です。
実現する機能は、クライエントから送信された文字を返信するのです。
今回は、それ以外の機能は一切入れないプログラムを作りましょう!

プログラムの流れ

サーバーサイド

サーバ起動

->サーバー側のソケットを作る

-> クライエントからの接続リクエストを待つ

-> 接続を許可する

-> 受信待ち&処理ループ

-> クライエントからの停止シグナル(空データ)

-> ソケットを閉じる

  1. socketを作成する
    pythonでは、オフィシャルライブラリーsocketを提供していますので。そのままimportすれば使えるようになります。
    AF_INETの由来はlinuxのsocket callのパラメータです。ipv4を指定する。
    また、SOCK_STREAMはTCPを代表する。

    import socket
    server_socket = (socket.AF_INET,socket.SOCK_STREAM)
    

    これで新しいソケットを作成しました。

  2. bind() サーバーのsocketをサインする
    socketを利用するには、必ずportとipアドレスを指定する。

    サーバーの場合ipアドレスは必ず自身のipを指定すること。

    server_socket.bind(("127.0.0.1",12345))
    

    明らかに、複数のsocketを一つのportにバインディングしていけない

  3. listen() 遠方アドレスの行列を作る
    listenのところに入らった、クライント側から受信するまで、プログラムはここでブロックされます。

    server_socket.listen(1)
    

    listen()の引数はbacklogの数を指定するのです。backlog

    待てるクライエントのsocketの数を指定します。0に設定すると、一番最初に来たクライエントsocketをキューに押したら、後に来てくるすべてのsocketを拒みます。

  4. accept Finally,I accepted you.

    listen()はただ「socketが来た」との情報をサーバーサイドに知らせるだけです。その後accpet()でキューからsocketを取り、接続します。

    accept()は2つの戻り値値を返しています。

    • sock: socket オブジェクト
    • addr: Turpleオブジェクト。接続先のsocketにバインディングしているアドレス
    client_socket,client_address = server_socket.accept()
    

    これで接続ができました

  5. 受信処理

    基本的にはWhile Trueを使って無限ループで処理します

    • recv() bufferを設置
      socketでデータを伝送するには、送信でも受信でもbufferサイズを指定する必要があります。pythonでは、データを受信する同時にbufferサイズを設置します。
    data = client_socket.recv(1024)
    

    受信したデータをサーバのコンソールに示したい場合は、dataをdecodeする必要があります。

    str_data = data.decode()
    print("Received from client",str_data)
    
  • send()
    受信が成功でしたら、すぐ処理できるようになります。今回作りたいのはechoサーバーなので、受信したデータを直接返信すれば良いです。
    TCPで通信する場合はsend()を使います。ちなみに一方UDPの場合はsendto()という関数があります。

    client_socket.send(data)
    
    • close() 送信側からサービス停止シグナル(ここは空データを約束したif not data : break)を受けたら、クライエントのソケットを閉じる。サーバーサイドのソケットは次の接続を処理することができるようになりました。
    client_socket.close()
    

クライエント

クライエント起動
-> ソケットを作成
-> サーバーに接続
-> ユーザー入力処理/発送/受け取る
-> ユーザーが空データを入力したらクライエントを停止する

1.socketを作成する

サーバー側と同じです。

client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

2.connect() サーバーに接続します

client_socket.connect(("127.0.0.1",45621))

3.send() 送信

ネットワークにデータを送信する時に、必ず encodeすること。

client_socket.send(data.encode())

4.recv受信

client_socket.recv(1024)

5.close() クライエント側のsocketを閉じる

client_socket.close()

全体コード

#server
from os import terminal_size
import socket
server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_socket.bind(("127.0.0.1",45621))
server_socket.listen(1)
client_socket,client_address = server_socket.accept()
print("Connection from",client_address)
while True:
  data = client_socket.recv(1024)
  str_data = data.decode()
  if not data : break
  print("Received from client",str_data)
  client_socket.send(data)
#client_address.close()
client_socket.close()
#client
import socket

client_socket = socket.socket()
client_socket.connect(("127.0.0.1",45621))
while True:
  data = input(">")
  client_socket.send(data.encode())
  if  not data:break
  newData = client_socket.recv(1024)
  print("Received from server:" ,str(newData.decode()))
client_socket.close()

次回

複数のユーザーに対する処理

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1