それはうまくいきません。Sinatra のサーバーは http プロトコルと呼ばれる言語を理解し、話すため、次の文字列を送信します。
"This is a text please work"
ソケットを介して Sinatra アプリに接続することは、絶望的な祈りです。
プロトコルとは、クライアントとサーバーがどのように対話するかを指定する一連のルールです。これにより、各当事者は相手の発言を正確に理解できます。http プロトコルの場合、クライアントは として知られるものを送信しa request
、サーバーは として知られるもので応答しますa response
。要求と応答は、http プロトコルで指定された規則に従って正確にフォーマットする必要があります。リクエストの詳細は次のとおりです。
http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html
したがって、あなたの Java プログラムはa request
Sinatra のサーバーに送信する必要があります。これは、正確な方法でフォーマットされた単純な文字列です。単純な GET リクエストは次のようになります。
GET /path/to/page HTTP/1.1
Host: localhost:4567
ページの GET リクエストを行う場合:
http://localhost:4567/page1
(つまり、シナトラ ルートをヒットget '/page1'
)
...そのページに対する単純な GET リクエストは次のようになります。
GET /page1 HTTP/1.1
Host: localhost:4567
また、使用している OS に関係なく、http 要求のすべての行を「\r\n」で終了する必要があります。これらの 2 つの文字は、http プロトコルの一部です。さらに、最後のヘッダーの後には、次のように別の「\r\n」で示される空白行が必要です。
GET /page1 HTTP/1.1\r\nHost: localhost:4567\r\n\r\n
ここにJavaがあります:
import java.io.*;
import java.net.*;
public class Sinatra {
private static void contactServer() {
try {
Socket sock = new Socket("localhost", 4567);
OutputStream os = sock.getOutputStream();
PrintWriter writer = new PrintWriter(os);
String[] text = {
"GET /page1 HTTP/1.1",
"Host: localhost:4567",
};
String request = "";
for(int i=0; i < text.length; ++i) {
request += text[i] + "\r\n";
}
request += "\r\n";
System.out.println(request);
writer.write(request);
writer.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Sinatra.contactServer();
}
}
注:そのJavaプログラムを最初に数回実行したとき、サーバー(私が開始した$ ruby myapp.rb
)は次のエラーをスローしました:
[2013-08-19 20:10:11] ERROR Errno::ECONNRESET: Connection reset by peer
/Users/7stud/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/webrick/httpserver.rb:80:in `eof?'
/Users/7stud/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/webrick/httpserver.rb:80:in `run'
/Users/7stud/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/webrick/server.rb:191:in `block in start_thread'
しかし、Java プログラムをさらに数回実行すると、サーバーは最終的に動作しました。そのエラーの原因がわかりません。FireFox に URL を入力すると、サーバーはそのエラーをスローしませんでした。そこで、Firebug を使用して Firefox が送信するリクエストを確認しました。次に、Java プログラムで同じ要求ヘッダーをすべて使用しましたが、サーバーはまだそのエラーをスローしました。
編集:ソケットを閉じる前にJavaプログラムを1秒間スリープさせることで、サーバーエラーを解消できます。明示的にソケットを閉じるか、プログラムが終了すると、ソケットは閉じます。スリープがなければ、サーバーがまだリクエストを処理している間にソケットが閉じると思います。ブラウザはソケットを開いたままにするため、ブラウザがサーバーにそのエラーをスローさせることはありません。
Ruby クライアントでも同じサーバー エラーが発生します。
require 'socket'
port = 4567
host = 'localhost'
s = TCPSocket.new host, port
req = [
"GET /page1 HTTP/1.1",
"Host: localhost:4567",
"Accept: */*",
]
req = req.join("\r\n") << ("\r\n" * 2)
print req
s.write req
s.flush
#sleep(1)
s.close
そして、修正は同じです。唯一の些細な詳細は、curl
UNIXコマンドがサーバーにそのエラーをスローさせない理由です。
$ curl -v http://localhost:4567/page1
* About to connect() to localhost port 4567 (#0)
* Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 4567 (#0)
> GET /page1 HTTP/1.1
> User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8r zlib/1.2.3
> Host: localhost:4567
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/html;charset=utf-8
< Content-Length: 0
< X-Xss-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< Server: WEBrick/1.3.1 (Ruby/1.9.3/2012-04-20)
< Date: Tue, 20 Aug 2013 04:59:16 GMT
< Connection: Keep-Alive
<
* Connection #0 to host localhost left intact
* Closing connection #0
-v オプションを指定すると、curl はリクエストとレスポンスを出力します。curl を使用してリクエストを行ったが、サーバーがそのエラーをスローするのを見たことがない。curlも寝るのかな?