ホームページ  >  記事  >  バックエンド開発  >  Python の SimpleHTTPServer ソース コードと組み合わせてソケット通信を解析します

Python の SimpleHTTPServer ソース コードと組み合わせてソケット通信を解析します

WBOY
WBOYオリジナル
2016-07-06 13:29:471116ブラウズ

ソケットとは
コンピューターは、その名前が示すように、計算に使用されます。そのため、計算が必要な条件を入力し、計算結果を出力する入出力も必要となります。これらの入出力はI/O(入出力)として抽象化できます。

Unix コンピューターは、ファイルの抽象化を通じて IO を処理します。入出力、つまり異なるコンピュータープロセス間の通信もあります。したがって、この通信もファイルの抽象ファイル記述子を通じて実行されます。

同じコンピューター上で、プロセスはこのように通信できます。異なるコンピューターの場合はどうなるでしょうか?ネットワーク上のさまざまなコンピュータも通信できるため、ネットワーク ソケットを使用する必要があります。ソケットは、異なるコンピューター間の通信を抽象化したものです。彼は、TCP/IP プロトコルのアプリケーション層とトランスポート層の間の抽象化に取り組んでいます。以下に示すように:

2016627161931394.jpg (542×476)

サーバー通信
ソケットは、異なるコンピュータ間の通信、つまりネットワーク通信を保証します。 Web サイトの場合、通信モデルはクライアント/サーバー通信です。両端はソケット オブジェクトを確立し、ソケット オブジェクトを通じてデータを送信します。通常、サーバーはワイヤレス ループ内でクライアントの接続を待機しています。

2016627162000798.jpg (478×491)

ソケット通信例
ソケットインターフェースはオペレーティングシステムによって提供され、オペレーティングシステムを呼び出すためのインターフェースです。もちろん、高級言語は通常、便利な関数インターフェイスをカプセル化します。これは、Python コードを使用した単純なソケット サーバーの例です。

サーバー.py

リーリー
client.py

リーリー

TCP スリーウェイ ハンドシェイク
Python コードでソケットを記述するのは簡単です。伝説の TCP スリーウェイ ハンドシェイクはどのように具体化されるのでしょうか?スリーウェイハンドシェイクとは何ですか?

最初のハンドシェイク: まず、クライアントは syn を送信して接続をリクエストします。 2 回目のハンドシェイク: サーバーは受信後に確認し、同期応答を送信します

3 番目のステップ: サーバーから応答を受信した後、クライアントは接続を確立するためにサーバーに確認を送信します。
次の比喩を使用してください

C: 予約を取りますか?

S:

について

C: わかりました

デート

これにより、TCP 接続セッションが確立されます。切断したい場合の一般的なプロセスは次のとおりです:



2016627162110796.png (416×209)上の写真は、スリーウェイ ハンドシェイク ソケットの具体的なプロセスも明確に示しています。

connect を呼び出した後、クライアント ソケット オブジェクトはブロックされます。このプロセスは syn を送信します。
  • サーバーソケットオブジェクトは、accept 関数を呼び出した後、クライアントから syn が送信されるまでブロックし、その後 syn 応答と ack 応答を送信します
  • クライアント ソケット オブジェクトは、サーバーから送信された応答を受信した後、サーバーに ack を送信し、connect 呼び出しを返して接続を確立します。
  • サーバーソケットオブジェクトはクライアントの最後のハンドシェイクを受け入れ、ackを確認し、accept関数を返し、接続を確立します。
  • この時点で、クライアントとサーバー間のソケット通信接続が確立され、残りは両端の接続オブジェクトがデータを送受信してネットワーク通信を完了します。


シンプルHTTPサーバー

単純な HTTP サービスを構築するには、HTTPServer を継承する必要があり、リクエストハンドラーも BaseHTTPRequestHandler を継承する必要があります。 Python は SimpleHTTPServer という例を実装しています。したがって、SimpleHTTPServer を分析して、以前のクラスのいくつかを使用して http サービスを構築する方法を確認します。
Python のシンプルさと優雅さを示すために、Python では 1 行のコードでサーバーを起動できる例がよく挙げられました。

リーリー

ここでの SimpleHTTPServer は HTTPServer を実装するモジュールです。

SimpleHTTPServer は、BaseHTTPServer モジュールのテスト メソッドをエントリ ポイントとして使用します。

リーリー

テスト メソッドは 2 つのことを行います。1 つ目は、HTTPServer を使用してリスニング アドレスと requestClass パラメーターを受け取り、インスタンス オブジェクトを作成し、server_forever メソッドを呼び出してサービスを開始することです。

1.SimpleHTTPRequestHandler

前の分析によると、httpserver サービスを使用するには、BaseHTTPRequestHandler を継続し、イントロスペクション メソッドを提供するだけで済みます。
リーリー

do_GETとdo_HEADはそれぞれhttp getリクエストとheadリクエストの処理を実装します。 send_head メソッドを呼び出します:

リーリー

send_head メソッドは、uri のパス分析を通じて顧客が要求したネットワーク パスを取得します。 head の MIME メタ情報を構築してクライアントに送信し、パスを開くためのファイル ハンドルを返します。

2.ファイルをコピー

do_GET の次のステップは、顧客が要求したパスのファイル データを、copyfile メソッドを通じてバッファされた書き込み可能なファイルに書き込み、クライアントに送信することです。

3.list_directory
SimpleHTTPServer模块还提供了list_directory方法,用于响应path是一个目录,而不是文件的情况。

def list_directory(self, path):
  try:
    list = os.listdir(path)
  except os.error:
    self.send_error(404, "No permission to list directory")
    return None
  list.sort(key=lambda a: a.lower())
  f = StringIO()
  displaypath = cgi.escape(urllib.unquote(self.path))
  f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
  f.write("<html>\n<title>Directory listing for %s</title>\n" % displaypath)
  f.write("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath)
  f.write("<hr>\n<ul>\n")
  for name in list:
    fullname = os.path.join(path, name)
    displayname = linkname = name
    # Append / for directories or @ for symbolic links
    if os.path.isdir(fullname):
      displayname = name + "/"
      linkname = name + "/"
    if os.path.islink(fullname):
      displayname = name + "@"
      # Note: a link to a directory displays with @ and links with /
    f.write('<li><a href="%s">%s</a>\n'
        % (urllib.quote(linkname), cgi.escape(displayname)))
  f.write("</ul>\n<hr>\n</body>\n</html>\n")
  length = f.tell()
  f.seek(0)
  self.send_response(200)
  encoding = sys.getfilesystemencoding()
  self.send_header("Content-type", "text/html; charset=%s" % encoding)
  self.send_header("Content-Length", str(length))
  self.end_headers()
  return f

由此可见,处理客户端的请求,只需要使用 send_reponse, send_header 和 end_headers ,就能向客户端发送reponse。

4.自定义http服务
定义一个CustomHTTPRequestHadnler继承自BaseHTTPRequestHandler。在其内实现do_GET 方法来处理get请求。

然后再定义一个CustomHTTPServer继承自HTTPServer,它接受CustomHTTPRequestHadnler作为自己的handler。简单的代码如下:

# -*- coding: utf-8 -*-

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer


class CustomHTTPRequestHandler(BaseHTTPRequestHandler):
  def do_GET(self):
    self.send_response(200)
    self.send_header('Content-type', 'text/html')
    self.end_headers()
    self.wfile.write("hello world\r\n")


class CustomHTTPServer(HTTPServer):
  def __init__(self, host, port):
    HTTPServer.__init__(self, (host, port), CustomHTTPRequestHandler)


def main():
  server = CustomHTTPServer('127.0.0.1', 8000)
  server.serve_forever()


if __name__ == '__main__':
  main()

使用curl访问可以得到

&#10140; ~ curl http://127.0.0.1:8000
hello world
&#10140; ~

控制台会打出访问的log。

127.0.0.1 - - [01/Jun/2015 11:42:33] "GET / HTTP/1.1" 200 -

从socket的建立,select的IO模式,再到Server和Handler的组合构建服务。我们已经熟悉了python的基本网络编程。python的web开发中,更多是使用WSGI协议。实现该协议的还有 uWSGI和gunicorn等库。相比那些库,python内部提供了一个wsgiref模块,实现了一个简单wsgi服务--simple_server。

接下来将会通过分析simple_server,更好的掌握WSGI协议。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。