標準ライブラリ

ネットワークインターフェイス

ネットワーキングインターフェイスとIPC,上位レベルのURLインターフェイスについて解説します。

関数パッケージ
socket()socket
bind()socket
listen()socket
accept()socket
connect()socket
send()socket
sendall()socket
recv()socket
urllib.request()urllib.request
build_opener()urllib.request
install_opener()urllib.request
socketserver.TCPServer()socketserver
socketserver.serve_forever()socketserver
socketserver.UDPServer()socketserver

TCP/IP接続

 TCP/IPで接続した通信路を使ってデータを送受信します。ここではsocketインターフェイスを使っています。socketは BSD UNIX のsocketインターフェイスと同じものです。

 以下はエコーサーバーを実装した受信側の例です。使用できるインターフェイスからの接続を待ちます。データを受信すると受信データを送信側にエコーします。

import socket

HOST = ''                 # すべての利用できるインターフェイス
PORT = 50007              # 未使用のポート
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen(1)
    conn, addr = s.accept()
    with conn:
        print('接続されました by', addr)
        while True:
            data = conn.recv(1024)
            if not data: break
            conn.sendall(data)

 送信側のコードです。

import socket

HOST = 'daring.cwi.nl'    # リモートホスト エコーサーバー
PORT = 50007              # サーバーが使用しているポートと同じ番号を指定します
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    s.sendall(b'Hello, world')
    data = s.recv(1024)
print('受信データ', repr(data))

インターネットリソースを取得する

 urllibパッケージを用いて、インターネットリソースをフェッチします。

 以下の例では、指定URLのデータを300バイト取得します。

>>> import urllib.request
>>> with urllib.request.urlopen('https://www.cnn.co.jp') as f:
...     print(f.read(300))
... 
b'<!DOCTYPE html>\r\n<html lang="ja">\r\n<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article#">\r\n    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">\r\n<title>CNN.co.jp</title>\r\n<meta name="title" content="CNN.co.jp">\r\n<meta name="description" c'
>>> 

基本(ベイシック)認証を使ってインターネットアクセス

 ベーシック認証を使ってインターネットリソースにアクセスします。

import urllib.request
#   HTTP ベーシック認証を使う
auth_handler = urllib.request.HTTPBasicAuthHandler()
auth_handler.add_password(realm='PDQ Application',
                          uri='https://mahler:8092/site-updates.py',
                          user='klem',
                          passwd='kadidd!ehopper')
opener = urllib.request.build_opener(auth_handler)
# openerを大域的に使う
urllib.request.install_opener(opener)
urllib.request.urlopen('http://www.example.com/login.html')

TCPサーバーを作成する

 TCPサーバーを作成してネットワークサービスを提供します。socketserverパッケージを使います。以下はサーバーサイドの例です。

import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):
    """
  サーバーのハンドラークラスの定義
  クライアントと通信する場合は、handle()メソッドを実装してください
    
    """

    def handle(self):
        # self.request クライアントとTCP socket 接続する
        self.data = self.request.recv(1024).strip()
        print("{} wrote:".format(self.client_address[0]))
        print(self.data)
        # 受信データを大文字に変更し、返送する
        self.request.sendall(self.data.upper())

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999

    # サーバーを作成し, localhostのポート 9999 にバインドする
    with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
        # Ctrl-C で終了させるまで、稼働を続ける。
        server.serve_forever()

クライアント側の例を以下に記します。コマンドラインから引数として送信文字列を入力します。引数で受け取ったデータをサーバーに送信します。

import socket
import sys

HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])

# (SOCK_STREAM型の(TCP socket)ソケットを作成する
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    # サーバーに接続してデータを送信
    sock.connect((HOST, PORT))
    sock.sendall(bytes(data + "\n", "utf-8"))

    # サーバーから返信データを受信して終了する
    received = str(sock.recv(1024), "utf-8")

print("Sent:     {}".format(data))
print("Received: {}".format(received))

UDPサーバーを作成する

 UDPサーバーを作成します。TCPサーバーと同様ですが、UDPはデータの送受信確認をしないため、TCPより高速に送受信できますが通信データは保証されません。パケットのロスが許容できる音声データの通信等で用います。

import socketserver

class MyUDPHandler(socketserver.BaseRequestHandler):
    """
    
    """

    def handle(self):
        data = self.request[0].strip()
        socket = self.request[1]
        print("{} wrote:".format(self.client_address[0]))
        print(data)
        socket.sendto(data.upper(), self.client_address)

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    with socketserver.UDPServer((HOST, PORT), MyUDPHandler) as server:
        server.serve_forever()

クライアント側のコードです。UDPパケットを送信します。

import socket
import sys

HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])

# SOCK_DGRAM (UDP)ソケット
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# UDPは接続を必要としないためconnect()システムコールは使いません。
# データは sendto() システムコールで受信側に直接送信します。
sock.sendto(bytes(data + "\n", "utf-8"), (HOST, PORT))
received = str(sock.recv(1024), "utf-8")

print("Sent:     {}".format(data))
print("Received: {}".format(received))

-標準ライブラリ
-, , ,