DIY Webサーバー

最近、単純な「Webサーバー」を作成する例によって、特定のプログラミング言語に注意を引くことに関するいくつかの投稿がありました。 そのような perl はまだ触れられていないので、私は自分の5セントを追加します:)
httpサーバーを装ったシンプルなサーバーアプリケーションを作成します。


「サーバー」は、ローカルポート8080をリッスンし、適用するすべてのユーザーに挨拶するか、要求されたファイルが存在する場合(スクリプトサーバーが起動されたフォルダー内)のコンテンツを返します。

手始めに、シンプルで短いコード。 この段階では、コメントするために特別なことは何も必要ないので、後でコメントを残してください。
  1. #!/ usr / bin / perl
  2. LWP :: Socketを 使用し ます。
  3. $ headers = "HTTP / 1.1 200 OK \ r \ n Content-Type:text / html \ r \ n \ r \ n " ;
  4. $ sock = new LWP :: Socket ;
  5. $ sock- > bind '127.0.0.1' '8080' ;
  6. $ sock- > listen 10 ;
  7. while $ socket = $ sock- > accept 10 {
  8. $ content = "Habr from Habr" ;
  9. $ file_name ; $ socket- > read \ $ file_name ;
  10. $ file_name = 〜s / GET \ /([^] *)HTTP。+ / $ 1 / s ;
  11. if open FILE '<' $ file_name {
  12. $ content = join "" <FILE> ; FILEを閉じ ます。
  13. }
  14. $ socket- > write $ headers $ content ;
  15. $ socket- > shutdown ;
  16. }

これはいコードです。書かない方がいいです。この例は、必要な機能が、必要に応じて、十分な速度で少量のコードで実装できることを示すためのものです。

このコードは、高貴で補足する必要があります。 それをもう少し読みやすくし、指定されたポートにバインドできたかどうかを確認するチェックを追加します(そうでない場合は既にビジーです)。
  1. #!/ usr / bin / perl
  2. strictを使用し ます。
  3. 警告を使用します
  4. LWP :: Socketを 使用し ます。
  5. my $ headers = "HTTP / 1.1 200 OK \ r \ n Content-Type:text / html \ r \ n \ r \ n " ;
  6. 私の $ sock = new LWP :: Socket ;
  7. die $ sock- > bind '127.0.0.1' '8080' )で ない限り 、「ソケットをバインドできません」 ;
  8. $ sock- > listen 10 ;
  9. while my $ socket = $ sock- > accept 10 {
  10. 私の $ content = "Habr from Habr" ;
  11. 私の $ file_name ;
  12. $ socket- > read \ $ file_name ;
  13. $ file_name = 〜s / GET \ /([^] *)HTTP。+ / $ 1 / s ;
  14. if -f $ file_name and open FILE '<' $ file_name {
  15. $ content = join "" <FILE> ;
  16. FILEを閉じ ます。
  17. }
  18. $ socket- > write $ headers $ content ;
  19. $ socket- > shutdown ;
  20. }
  21. $ sock- > shutdown ;

あと数行だけですが、スクリプトはもう少し文化的になりました。

ここにあります

use LWP::Socket;
必要なモジュールを接続します。 とても使いやすいので、私はそれを選びました。

my $sock = new LWP::Socket();
ソケットを作成する

$sock->bind('127.0.0.1', '8080');
$sock->listen(10);

ソケットをローカル8080ポートにバインドし、キューの長さを設定します

while ( my $socket = $sock->accept(10) ) {
接続待ち
$ソケットに接続すると、新しいLWP :: Socket()が返されます

$socket->read( \$file_name );
$file_name =~ s/GET \/([^ ]*) HTTP.+/$1/s;

ソケットからすべてを読み取り、要求されたファイルの名前を取得します

$socket->write( $headers . $content );
ヘッダーへの書き込みとソケットへの応答

$socket->shutdown();
「セッションごと」に受信したLWPを閉じる:: Socket()

これは終了することもできますが、http-serverになりすましたいので、負荷に耐えるためにマルチスレッドが必要です:)
これを行うには、FCGI :: ProcManagerモジュールを使用します。その結果、1つの「ヘッド」プロセスと5つの子があります。 これを行うには、次の4行のみを追加します。
  1. #...
  2. LWP :: Socketを 使用し ます。
  3. FCGIを使用 :: ProcManager qw / pm_manage pm_pre_dispatch pm_post_dispatch / ;
  4. my $ headers = "HTTP / 1.1 200 OK \ r \ n Content-Type:text / html \ r \ n \ r \ n " ;
  5. 私の $ sock = new LWP :: Socket ;
  6. die $ sock- > bind '127.0.0.1' '8080' )で ない限り 、「ソケットをバインドできません」 ;
  7. $ sock- > listen 10 ;
  8. pm_manage n_processes => 5 ;
  9. while my $ socket = $ sock- > accept 10 {
  10. pm_pre_dispatch ;
  11. 私の $ content = "Habr from Habr" ;
  12. #...
  13. $ socket- > shutdown ;
  14. pm_post_dispatch ;
  15. }
  16. $ sock- > shutdown ;

これで、「サーバー」の準備ができました。 :)を使用できます。 完全なコードを提供して、ファイルに単純にコピーし、実行し、すべてが機能することを確認できるようにします。
少し追加したこのコード:
-追加されたヘッダー
-「あいさつ」がインデックスページとして提供されます
-残りとして-何が尋ねられます
-ファイルが見つからない場合、ブラウザにこの404エラーについて通知します
-コメントを追加しました
  1. #!/ usr / bin / perl
  2. strictを使用し ます。
  3. 警告を使用します
  4. LWP :: Socketを 使用し ます。
  5. FCGIを使用 :: ProcManager qw / pm_manage pm_pre_dispatch pm_post_dispatch / ;
  6. #ヘッダーを準備する
  7. my $ headers = "HTTP / 1.1%d OK \ r \ n "
  8. 「サーバー:FakeServer / 2009-09-12 \ r \ n
  9. 「コンテンツタイプ:text / html \ r \ n
  10. 「コンテンツ長:%d \ r \ n
  11. 「接続:閉じる\ r \ n \ r \ n ;
  12. #ソケットを準備して開く
  13. 私の $ sock = new LWP :: Socket ;
  14. die $ sock- > bind '127.0.0.1' '8080' )で ない限り 、「ソケットをバインドできません」 ;
  15. $ sock- > listen 10 ;
  16. #子を5つ作成する
  17. pm_manage n_processes => 5 ;
  18. #新しい接続を受け入れます
  19. while my $ socket = $ sock- > accept 10 {
  20. #子に方向を渡す
  21. pm_pre_dispatch ;
  22. #デフォルトのコンテンツ
  23. my $ content = "<html> <body> <h1> Habrからこんにちは</ h1> </ body> </ html>" ;
  24. 私の $ stat = 200 ;
  25. 私の $ file_name ;
  26. #ソケットから読み取る
  27. $ socket- > read \ $ file_name ;
  28. #必要なファイル名を取得
  29. $ file_name = 〜s / GET \ /([^] *)HTTP。+ / $ 1 / s ;
  30. if $ file_name {
  31. if -f $ file_name and open FILE '<' $ file_name {
  32. #ファイルから読み取る
  33. $ content = join "" <FILE> ;
  34. FILEを閉じ ます。
  35. }
  36. その他 {
  37. $ content = "ファイルが見つかりません" ;
  38. $ stat = 404 ;
  39. }
  40. }
  41. #ヘッダーとコンテンツをソケットに入れます
  42. $ socket- > write sprintf $ headers $ stat length $ content ;
  43. $ socket- > write $ content ;
  44. $ socket- > shutdown ;
  45. #子供の仕事完了
  46. pm_post_dispatch ;
  47. }
  48. #ソケットを閉じる
  49. $ sock- > shutdown ;


使用説明書:
-コードをコピーしてファイルに貼り付けます
-実行(perl file.pl)
-ブラウザでhttp://127.0.0.1:8080 /を開きます

最後のオプションで誰も怖がらないことを願っています:)

PS誰かが興味を持っている場合、10人の子供を持つこのケースは15メートルのRAMを食べ、30スレッドでリクエストをテストすると、毎秒約2000リクエストを処理できました(10スレッドは既存のファイルをリクエストしました) ローカルマシンで実行し、テストでは両方のコアが天井の下にロードされました。

---------
ここからのバックライト

Source: https://habr.com/ru/post/J69411/


All Articles