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

Python自作プログラム(Pyhttpd)徹底解説!!

More than 1 year has passed since last update.

概要

前回の記事では私が作った自作プログラムのソースと、ソースを理解するためのPythonにおけるクラスなどの基本について解説しました。
今回の記事では前回載せたソースについて詳しく解説していきます。

プログラム徹底解説

モジュールインポート

pyhttpd.py
import BaseHTTPServer

これは前回の記事でも説明した通り、PythonでHTTP通信をするために作成された他のプログラムを使用するために読み込ん(インポート)でいます。
BaseHTTPServerに関するメソッドやインスタンスについてはこちらのマニュアルを参考にしてみてください。

クラス定義

pyhttpd.py
class MyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

このプログラムでPOST、GETを使うためのクラスを定義します。
このクラスを定義し、その中でPOSTとGETのメソッドをしてインスタンス化することでPOSTとGET機能を使えるようになります。
()の中にBaseHTTPServer.BaseHTTPRequestHandlerという記述がありますが、
これはクラスの継承と呼ばれるものです。
クラスを定義する際に他のクラスをここに書くことで、書いたクラスのメソッドやインスタンスを使うことができます。

メソッド定義

pyhttpd.py
def do_POST(self):

def do_GET(self):

実際にGET、POSTの処理を定義するメソッドを定義します。
メソッド名は基本的に自由につけることができますが、
今回の場合はBaseHTTPServerモジュールの中で「do_」というメソッド名をつけることで自動的にPOST・GETリクエストに対してメソッドを呼び出してくれます。

selfはメソッドを定義する際には必ず必要となる第1引数です。
メソッドがインスタンスやクラス変数などにアクセスする際に必要になるものであると考えてください。

メソッドの中の詳細

pyhttpd.py
#全インスタンス定義
1       client_address = self.client_address
2       server = self.server
3       path = self.path
4       request_version = self.request_version
5       server_version = self.server_version
6       sys_version = self.sys_version
7
8       #content_len = int(self.headers.get('content-length'))
9       #requestbody = self.rfile.read(content_len).decode('utf-8')
10      #print(content_len)
11      #print('requestbody=' + requestbody)
12      print('client_address = ' + client_address[0] + ' ' + str(client_address[1]))
13      print('server = ' + server.server_name + ' ' + str(server.server_port))
14      print('path = ' + path)
15      print('request_version = ' + request_version)
16      print('server_version = ' + server_version)
17      print('sys_version = ' + sys_version)
18      self.send_response(200)
19      self.end_headers()
20
21      # POSTリクエストに対して返却するHTMLを記述
22      f = open("/usr/local/scripts/put.html",'r')
23      self.wfile.write(f.read())
24      f.close()

1~6行目についてはこのメソッドの中で使う変数を定義しています。
self.client_addressとありますが、
継承したBaseHTTPServer.BaseHTTPRequestHandlerクラスの中にはclient_addressというインスタンスが定義してあり、
このself引数を使用してclient_addressというインスタンスにアクセスしています。

12~17行目は取得したインスタンスの中身を出力しています
18行目はクライアントからPOSTリクエストが来た際に返すステータスコードを定義しています。
実際にPSOTリクエストを送ると以下のようなレスポンスが返ってきます。

HTTP/1.0 200 OK

この200が18行目で定義した200にあたります。
19行目はここでヘッダーに返す部分が終了することを表します。
これ以降に書かれた部分についてはメッセージボディ部分でクライアントに返されます。

22~24行目で実際にクライアントに返すメッセージボディ部分を定義します。

pyhttpd.py
f=open('/usr/local/scripts/put.html', 'r')

ここでPOSTリクエストが来た際に返されるhtmlをここで開いています。
Pythonでファイルを扱う場合はファイルを読み込んで開き、処理を行う必要があります。
open関数を使って開き、close関数を使ってファイルを閉じます。
ここで実際に返しているput.htmlの中身は以下になります。

put.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>送信後ページ</title>
</head>
<body>
    <h1>データ送信後ページ</h1>
    <p>data was sent!</p>
</body>
</html>

open関数で返されるものはファイルオブジェクトになります。
23行目でメッセージボディとして返す内容(htmlファイル)をメモリに書き込みます。
24行目でopen関数によって開いたファイルを閉じています。
POSTリクエストではリクエストによって送信されてきたデータをこのメソッドの中で処理しているイメージになります。

pyhttpd.py
     self.send_response(200)
     self.end_headers()

     f = open("/usr/local/scripts/index.html", 'r')
     self.wfile.write(f.read())
     f.close()

これはGETメソッドの処理を定義しています。
既に解説したPOSTメソッドの処理とほとんど同じですので詳細は割愛します。

インスタンス生成

pyhttpd.py
server = BaseHTTPServer.HTTPServer(('192.168.15.80',50080),MyRequestHandler)
server.serve_forever()

クラスは定義しただけではメソッドなどを使えないと説明しました。
最初の部分で実際にクラスをインスタンス化
定義したクラスは

定義するインスタンス名 = クラス名()

のようにすることで定義します。
今回はHTTPの機能を使うためにインポートしたモジュールをインスタンス化しています。
BaseHTTPServer.HTTPServerクラスは引数として、

((<サーバーとして受け付けるIPアドレス>,ポート番号),メソッドの処理を定義したクラス)

をとります。
今回は「メソッドの処理を定義したクラス」を私が自分で定義したMyRequestHandlerを使用しています。

最後の

pyhttpd.py
server.serve_forever()

この部分で実際に作成したインスタンスからソケットを作成し、リクエストをリッスンしています。
このserve_forever()メソッドはSocketServerモジュールの中で定義してあるメソッドになります。
BaseHTTPServerモジュールはSocketServerモジュールを継承して作られているため、
SocketServerモジュールのメソッドも使用可能となっています。

まとめ

いかがでしたでしょうか。
以上が今回私が自作したプログラムの解説になります。
今回の説明でわかりにくい部分などがあればコメントなどを頂ければ詳しく解説いたします。

syuji-yoshiyoshi
とある会社のインフラエンジニア。 興味を持ったことには幅広く勉強中。 パイソニスタになるべく絶賛勉強中。 使っているOSは主にCentOSとRHEL。
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
ユーザーは見つかりませんでした