ネットワーキングインターフェイスと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))