質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.83%
HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

LISP

LISPはプログラミング言語の一種であり、関数型言語に分類されています。 特徴として、括弧を多様する独特の構文を持ちます。

Q&A

受付中

localhostへの接続が拒否される

DaiAoki
DaiAoki

総合スコア67

HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

LISP

LISPはプログラミング言語の一種であり、関数型言語に分類されています。 特徴として、括弧を多様する独特の構文を持ちます。

2回答

0グッド

4クリップ

93162閲覧

投稿2016/12/23 03:31

編集2016/12/25 05:45

『Land Of Lisp』という書籍で簡易的なWebサーバを作る章の勉強をしています。
ポート8080にソケットを開いて、ブラウザで以下(p259)を入力したのですが、接続が拒否されてしまいます。

http://127.0.0.1:8080/greeting

Lisp

1;;処理系はClispです 2(defun serve (request-handler) 3 (let ((socket (socket-server 8080))) 4 (unwind-protect 5 (loop (with-open-stream (stream (socket-accept socket)) 6 (let* ((url (parse-url (read-line stream))) 7 (path (car url)) 8 (header (get-header stream)) 9 (params (append (cdr url) 10 (get-content-params stream header))) 11 (*standard-output* stream)) 12 (funcall request-handler path header params)))) 13 (socket-server-close socket))))

以下のコマンドでポート8080が正常に機能していることは確認済みですので、localhostに接続できていないことが原因であると考えています。

lsof -i :8080

いろいろと解決策を調べている中で、以下は試しました。
・ファイアーウォールの設定で、Google Chrome.appの接続を許可
・プロキシの設定で、「プロキシ設定を使用しないホストとドメイン」に*.localがあることを確認

原因の調査方法・調査観点などをご教示いただければと思います。
よろしくお願いします。

【追記】
Apacheの起動を行なっていなかったため、以下コマンドでhttp://localhostと打ち込んで「It works!」と表示されるところまでは確認できたのですが、ポート8080に接続しようとすると反応のない状況です。

sudo apachectl start

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

suama

2016/12/23 05:48

インターネットとの接続を切ったが状態で、ファイアウォールも無効化して確認することはできますか?お手元のpcからだとは思いますが。もしくは、違うプロセスが8080番を使っているかもしれません。
ikedas

2016/12/23 09:50

ご提示のソースコードが何ページに載っているか明記して下さい (書籍を見られる方が確認できるように)。あと、コードは正確に引用されているでしょうか (ご提示のコードを見る限り、socketに何か代入している箇所がないのですが)。
DaiAoki

2016/12/25 04:49

> suamaさん 確認しましたが、「127.0.0.1 ページは機能していません ERR_INVALID_HTTP_RESPONSE」のエラーになりました。lsof -i :8080で調べると、COMMANDとして、lisp.runが8080を使っていることになっていたため、ポートの接続には問題ない状態です。
DaiAoki

2016/12/25 04:50

>ikedasさん ご指摘の通り修正しました。また、ソースコードについてもご指摘の通りsocketを定義する箇所が漏れていたため修正しました。
ikedas

2016/12/25 05:39

書籍で確認できていなくてすみませんが、修正いただいた後のコードでは (let …) の括弧が (unwind-protect …) の前で閉じています。「socket」の直前に「(」がもう1個いるのでは。
DaiAoki

2016/12/25 05:46

>ikedasさん ご指摘の通り誤記です。修正しました。

回答2

5

原著の公式サイトを見つけました。ソースコードが掲載されていて、ご質問のコードとも一致するようです。これで試してみます。書籍は未入手です。


ブラウザを使ってアクセスすると、サーバのレスポンスを直接見ることができません。telnetコマンドを使って手作業でリクエストを送信、レスポンスを受け取ることにします (最近のオペレーティングシステムではtelnetが入っていないことがあるので、なければインストールして下さい)。別の端末を開いて、次のように実行・入力します。

bash

1$ telnet localhost 8080 2Trying 127.0.0.1... 3Connected to localhost. 4Escape character is '^]'. 5GET /greeting HTTP/1.1 6Host: localhost:8080 7 8<form>What is your name?<input name='name' /></form>Connection closed by foreign host. 9$ 10```サーバが正しいレスポンスを返していません。接続はできているのに「ERR_INVALID_HTTP_RESPONSE」というエラーになるのはこのためでしょう。 11 12- 上で説明していることの意味がわからなければ、まず**HTTPというプロトコルについて調べて下さい** (HTTPについては文中でも多少説明があるだろうと思いますが、必要に応じて他の参考書もご覧下さい)13 14さて、以下いささか冗長とは思いますが、解決するために私がやったことを書きます。 15 16# 単体テスト 17 18いきなりプログラムを実行するのではなく、まず関数ごとにテストをしてみましょう。 19 20アクセスするURLを``http://localhost:8080/greeting``と想定します。クライアントが送るリクエストは、つぎのようなものになります (実際のブラウザが送るものはもっと複雑ですが、単純化しています)

GET /greeting HTTP/1.1
Host: localhost:8080
(空行)

プログラムをロードし、(サーバは起動せずに) ``parse-url``、``get-header``の動作をテストします。 ```lisp [1]> (load "webserver.lisp") ;; Loading file webserver.lisp ... ;; Loaded file webserver.lisp T [2]> (parse-url "GET /greeting HTTP/1.1") ("greeting") [3]> (get-header *standard-input*) Host: localhost:8080 ((HOST . "localhost:8080")) [4]> ```うまく動いているようです。 次に、リクエストハンドラをテストします。サンプルの``hello-request-handler``でやってみます。 ```lisp [4]> (hello-request-handler "greeting" '((HOST . "localhost:8080")) nil) <form>What is your name?<input name='name' /></form> "<form>What is your name?<input name='name' /></form>" [5]> ```最初にステータス行やレスポンスヘッダがありません。ソースコードの該当箇所を確認します。 ```lisp (defun hello-request-handler (path header params) (if (equal path "greeting") (let ((name (assoc 'name params))) (if (not name) (princ "<form>What is your name?<input name='name' /></form>") (format t "Nice to meet you, ~a!" (cdr name)))) (princ "Sorry... I don't know that page."))) ```ステータス行もレスポンスヘッダも出力していません。これでは正しいレスポンスになりません。コードを修正します。 ```lisp (defun hello-request-handler (path header params) (if (equal path "greeting") (let ((name (assoc 'name params))) (format t "HTTP/1.0 200 OK~C~C" #\return #\linefeed) (format t "Content-Type: text/html~C~C" #\return #\linefeed) (format t "~C~C" #\return #\linefeed) (if (not name) (princ "<form>What is your name?<input name='name' /></form>") (format t "Nice to meet you, ~a!" (cdr name)))) (progn (format t "HTTP/1.0 404 NG~C~C" #\return #\linefeed) (format t "Content-Type: text/html~C~C" #\return #\linefeed) (format t "~C~C" #\return #\linefeed) (princ "Sorry... I don't know that page."))) ) ```かなり手抜きですが、まあいいでしょう。もう一度やってみます。 ```lisp [4]> (hello-request-handler "greeting" '((HOST . "localhost:8080")) nil) HTTP/1.0 200 OK Content-Type: text/html <form>What is your name?<input name='name' /></form> "<form>What is your name?<input name='name' /></form>" [5]> ```うまくいったようです (あと、``/greeting``以外にアクセスした場合と、クエリパラメータがある場合は、ご自分でやってみて下さい)。 # 結合テスト 単体テストに通ったので、サーバを起動して全体の動作をテストしましょう。 ```lisp [2]> (serve #'hello-request-handler)

別の端末を開いて、次のように実行します。

bash

1$ telnet localhost 8080 2Trying 127.0.0.1... 3Connected to localhost. 4Escape character is '^]'. 5GET /greeting HTTP/1.1 6Host: localhost:8080 7 8HTTP/1.0 200 OK 9Content-Type: text/html 10 11<form>What is your name?<input name='name' /></form>Connection closed by foreign host. 12$ 13```正常なレスポンスを返しています (``/greeting``以外にアクセスした場合と、クエリパラメータがある場合は、ご自分でやってみて下さい)14 15最後に、ブラウザで正常にアクセスできることを確認します。 16 17--- 18私は書籍を読んでいないので推測ですが、著者にとってこのサンプルの目的は「こうすれば実現できる」と示すことであり、処理の細部は省いたのでしょう。読者のやりたいことに合わせて**自分でリクエストハンドラを書いて下さい**、ということかと思います。

投稿2016/12/26 03:40

ikedas

総合スコア3132

yonn, DaiAoki, ynakano, hotwatermorning, aaachi👍を押しています

下記のような回答は推奨されていません。

  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

DaiAoki

2016/12/26 15:52

>ikedasさん とても詳しいご説明ありがとうございます。順を追った解決方法、とても参考になりました。 telnetによる操作で正常に動作するところまで確認できたのですが、ブラウザでアクセスしようとすると拒否されてしまいます。 今後、ブラウザを使ったグラフィカルな開発の章に入っていくため、CUI以外からも確認したいと考えています。
ikedas

2016/12/27 03:39

「拒否されてしまう」とのことですが、ご覧になった通りサーバのプログラムにそういうことをする機能はないので、ブラウザが何か表示しているのだと思います。ブラウザの表示したエラーメッセージを具体的に教えて下さい。

0

telnetによる操作で正常に動作する

ということと、質問でプロキシの設定について触れられているのでlocalhost127.0.0.1がプロキシサーバーに流れているのでは?

・プロキシの設定で、「プロキシ設定を使用しないホストとドメイン」に*.localがあることを確認

この*.localhttp://example.local/などURLのFQDN部分が.localで終わっているものという意味になります。質問記載のURLでは http://127.0.0.1/http://localhost/なのでマッチしません。

以下を試してください。
・「プロキシ設定を使用しないホストとドメイン」にlocalhost127.0.0.1を念のため追加
・「ローカルアドレスにはプロキシサーバーを使用しない」をチェックする

投稿2016/12/27 05:09

編集2016/12/27 05:11
Y.H.

総合スコア7911

下記のような回答は推奨されていません。

  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.83%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

LISP

LISPはプログラミング言語の一種であり、関数型言語に分類されています。 特徴として、括弧を多様する独特の構文を持ちます。