I am able to send data to a sinatra server (Strings) but I'm not sure about how to actually receive it in the sinatra code. Could anyone help?
Java client (what i'm using to send data) code:
private static void contactServer() {
try {
String text = "This is a text please work";
Socket sock = new Socket("localhost", 4567);
OutputStream os = sock.getOutputStream();
URL url = new URL("http://localhost:4567/hello");
PrintWriter writer = new PrintWriter(os);
writer.flush();
writer.write(text);
url.openStream();
System.out.println("done");
String strTemp = "";
/*while(null != (strTemp = br.readLine())){
System.out.println(strTemp);
}*/
} catch (Exception e) {
e.printStackTrace();
}
}
That's not going to work. Sinatra's server understands and speaks a language called the http protocol, so sending the string:
"This is a text please work"
through a socket to a Sinatra app is a hopeless prayer.
A protocol is a set of rules that specify how the client and the server will speak to each other--then each party can understand exactly what other party is saying. For the http protocol, clients send something known as a request, and servers reply with something known as a response. The request and the response must be formatted precisely according to the rules specified by the http protocol. The gory details for a request are here:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html
So your java program needs to send a request to Sinatra's server, which is simply a string formatted in a precise manner. Here is what a simple GET request looks like:
GET /path/to/page HTTP/1.1
Host: localhost:4567
If you want to make a GET request for the page:
http://localhost:4567/page1
(i.e. hit the Sinatra route get '/page1')
...then a simple GET request for that page would look like:
GET /page1 HTTP/1.1
Host: localhost:4567
Also, you must end every line in the http request with "\r\n" no matter what OS you are using. Those two characters are part of the http protocol. Furthermore, after the last header there must be a blank line signified by another "\r\n", like this:
GET /page1 HTTP/1.1\r\nHost: localhost:4567\r\n\r\n
Here is the 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();
}
}
Note: the first few times I ran that java program, the server(which I started with $ ruby myapp.rb) threw the following error:
[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'
But when I ran the java program a few more times, the server eventually behaved. I have no idea what is causing that error. When I entered the url in FireFox, the server never threw that error. So I used Firebug to look at the request that Firefox sends; then I used all the same request headers in the java program, but the server still threw that error.
Edit: I can get the server error to go away by making the java program sleep for 1 second before closing the socket. The socket closes when you explicitly close the socket or when the program ends. Without the sleep, I think the socket closes while the server is still processing the request. Because a browser keeps the socket open, a browser never causes the server to throw that error.
The same server error also occurs with a ruby client:
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
And the fix is the same. The only niggling detail is why the curl unix command doesn't cause the server to throw that error:
$ 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
With the -v option, curl prints out the request and the response. Using curl to make the request, I never saw the sever throw that error. I wonder if curl does a sleep too?
Related
I am trying to have my client(s) connect their Dart (Flutter) running devices to my server running a Java ServerSocket. The connection establishes properly and all headers are received by the server, however no other data is received.
The configuration issue must be with the dart code below, since my other Java client to Java server with the same code works.
Dart client code:
// if the WebSocketChannel is not closed, close it
try {
channel?.sink.close();
} catch (e) {
// do nothing
}
channel = WebSocketChannel.connect(Uri.parse(globals.serverUrl));
channel?.sink.add("Test notification");
Java server code:
outStream = new PrintWriter(socket.getOutputStream(), true);
inStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
String input = inStream.readLine();
if (input == null) {
socket.close();
inStream.close();
outStream.close();
System.out.println("Client disconnected");
break;
}
System.out.println("Received: " + input);
}
Server output:
Received: GET / HTTP/1.1
Received: user-agent: Dart/2.17 (dart:io)
Received: connection: Upgrade
Received: cache-control: no-cache
Received: accept-encoding: gzip
Received: sec-websocket-version: 13
Received: host: localhost:8080
Received: sec-websocket-extensions: permessage-deflate; client_max_window_bits
Received: sec-websocket-key: lys/+BV+IIH5Mm52V0jUmw==
Received: upgrade: websocket
Received:
Note that the client does not disconnect, so the connection is indeed persistent.
The weird behaviour is with sending and receiving custom data:
Client to Server:
results in no data being sent or error showing
Server to Client:
[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: WebSocketChannelException: WebSocketChannelException: HttpException: Invalid response line, uri = http://localhost:8080/
The message transmitted from Server to Client here was just "test" and the client was listening with:
String? response = await channel?.stream.first;
The response would remain unused and was listened for after the completion of the sent message as seen in the Dart code sample.
I have a client application which send POST request(json) to a custom server. The server must send a response(json) to the incoming message, but i haven't detected any response on the client side.
The problem is not on the client's side, because if it sends a request to another server, then after a few seconds it receives a response and I see it in the logs.
SERVER CODE
try{
server = new ServerSocket(4321);
client = server.accept();
PrintWriter out = new PrintWriter(client.getOutputStream(), true);
System.out.println("Connection received from " + client.getInetAddress());
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
String s = "SERVER: Started.";
Gson gson = new Gson();
String json = gson.toJson(jsonObject.toString());
while ((s = in.readLine()) != null) {
System.out.println("RECV: "+s);
ss = s.split("PUSH\\s");
out.println("HTTP/1.1 200 OK");
out.println("application/json;charset=UTF-8");
out.println("application/json;charset=UTF-8");
out.println("Jersey/2.27 (HttpUrlConnection 1.8.0_291)");
out.println("no-cache");
out.println("no-cache");
out.println("hostname:4321");
out.println("keep-alive");
out.println("392");
out.println("\n");
out.println(json);
} catch(Exception e) {e.printStackTrace();}
I think the root of my issue is out.println(). I don't know exactly what the server should send back to client.
Response must contain json!
Also, i don't have the client code.
Could you help?
While I definitively wouldn't recommend writing an HTTP server this way there are at least two problems in your code:
You are missing header names, e.g. application/json;charset=UTF-8 should read Content-Type: application/json;charset=UTF-8
out.println() uses the line separator string as defined by the system property line.separator (e.g. \n for Linux). HTTP on the other hand needs \r\n, so better write it like this: out.print("HTTP/1.1 200 OK\r\n");
Try this:
out.print("HTTP/1.1 200 OK" + "\r\n");
out.print("Content-Type: application/json" + "\r\n");
// you shouldn't need the other headers…
out.print("\r\n");
out.print(json);
To understand the behaviour of the websocket, I created a simple SocketServer in java to exchange the messages. The server is expected to follow the operations as:
1) Listening at port 8080
2) A websocket handshake message generated manually on the browser client and received by the server.
3) Construct a response to the handshake message and reply to the client
4) Read out actually websocket info bytes with the same connection.
The problem has happened at step 4. when the server has responded with the handshake message, the InputStreamReader can no longer receive any new message. It blocked at the readline() method even though the client has sent the message already. From wireshark, I can see the client sent message and server respond ack. Any help would be appreciated, thanks.
Update: I just noted this question has been asked before. I will study the suggestions on the other posts first.
Update: The behavior is as same as this post:
Weird websocket behavior: only send data when close the tab
When the webtab closes, the read stream received the data package.
wireshark screen captures:
The tcp stream trace
The packages sequence
The log:
inputline: GET / HTTP/1.1
inputline: Host: localhost:8080
inputline: Connection: Upgrade
inputline: Pragma: no-cache
inputline: Cache-Control: no-cache
inputline: Upgrade: websocket
inputline: Origin: file://
inputline: Sec-WebSocket-Version: 13
inputline: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
inputline: Accept-Encoding: gzip, deflate, br
inputline: Accept-Language: en,zh-TW;q=0.8,zh;q=0.6,zh-CN;q=0.4
inputline: Sec-WebSocket-Key: Yin4xn04vr9iBH1b2dU15A==
inputline: Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
inputline:
response: HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: +Y9whLTzCdyN1INpAxjkO6yD2Nw=
The server socket code:
public class EchoServer {
public static String HTTP_VERSION_HEADER = "HTTP/1.1";
public static void main(String[] args) throws IOException {
int portNumber = 8080;
try (
ServerSocket serverSocket =
new ServerSocket(Integer.parseInt("8080"));
Socket clientSocket = serverSocket.accept();
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
) {
String inputLine;
StringBuilder sb = new StringBuilder();
while ( true) {
inputLine = in.readLine();
if(inputLine == null) {
System.out.println("input is null");
continue;
}
System.out.println("inputline: " + inputLine);
sb.append(inputLine).append(System.lineSeparator());
if(inputLine.equals("")) {
Message msg = new Message(sb.toString(), new Date());
HttpMessage tmpMessage = new HttpMessage(msg.getText(), new Date());
String response = generateHandshakeResponse(tmpMessage);
System.out.println("response: " + response);
out.println(response);
out.flush();
}
}
} catch (IOException e) {
System.out.println("Exception caught when trying to listen on port "
+ portNumber + " or listening for a connection");
System.out.println(e.getMessage());
}
}
private static String generateHandshakeResponse(HttpMessage message) {
String webSocketKey = message.getVal(HttpMessage.SEC_WEBSOCKET_KEY);
String webSocketAccept = webSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
byte[] bytes = DigestUtils.sha1(webSocketAccept);
String secWebSocketAcceptVal = Base64.encodeBase64String(bytes);
StringBuilder sb = new StringBuilder();
sb.append(HTTP_VERSION_HEADER).append(" 101 ").append("Switching Protocols\r\n");
sb.append("Upgrade: websocket\r\n");
sb.append("Connection: Upgrade\r\n");
sb.append("Sec-WebSocket-Accept: ").append(secWebSocketAcceptVal).append("\r\n");
sb.append("\n\n") //<--- this line fixed the problem
//log.debug(sb.toString());
return sb.toString();
}
}
The client code:
<!doctype html>
<html lang="en">
<head>
<title>Websocket Client</title>
</head>
<body>
<script>
var exampleSocket = new WebSocket("ws://localhost:8080");
exampleSocket.onopen = function (event) {
console.log("connection opened..");
exampleSocket.send("Can you hear me?");
};
exampleSocket.onmessage = function (event) {
console.log(event.data);
}
function sendMsg(){
console.log("send message..");
exampleSocket.send("hello hello");
}
</script>
<button onclick="sendMsg()" title="send">send</button>
</body>
</html>
Thanks a lot to EJP, the problem is a missing blank line at the response handshake to indicate the end of the message.
I am hosting a simple PHP echo server locally.
I am trying to send a message to the server in Java, and use a GET request to print the response but am getting a 'malformed HTTP request' error. Can anyone tell me how to correctly format the GET request?
//Client code:
import java.io.*;
import java.net.*;
public class TCPclient {
public static void main(String argv[]) throws Exception {
String sentence, modifiedSentence;
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
Socket clientSocket = new Socket("localhost", 8000);
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
sentence = inFromUser.readLine();
outToServer.writeBytes(sentence + "\n");
outToServer.writeChars("GET /echo.php HTTP/1.1" +"\n");
modifiedSentence = inFromServer.readLine();
System.out.println("FROM SERVER: " + modifiedSentence);
inFromServer.close();
outToServer.close();
inFromUser.close();
clientSocket.close();
}
}
//PHP Server code:
<?php
/* Simple php echo page
*/
// ini_set('display_errors', 'On');
// error_reporting(E_ALL | E_STRICT);
if(isset($_GET['source'])) {
if ($_GET['source'] == "raw")
echo file_get_contents(basename($_SERVER['PHP_SELF']));
else
echo "<pre>" . htmlspecialchars(file_get_contents(basename($_SERVER['PHP_SELF']))) . "</pre>";
} else if (isset($_GET['message'])){
echo strtoupper( htmlspecialchars($_GET['message'])) . '\n';
} else {
?>
<html>
<head>
<title>Error: No input message</title>
</head>
<body>
<h1> No message</h1>
<p>Echo server called without sending parameter</p>
</body>
</html>
<?php
}
?>
An http server understand words like GET, POST, PUT, DELETE. So here's a problem:
outToServer.writeBytes(sentence + "\n");
outToServer.writeChars("GET /echo.php HTTP/1.1" +"\n");
The first statement there is telling something to the http server that it doesn't understand: the sentence. Comment out that line and your request becomes valid, and you will get a response.
I guess you want to post the sentence as a parameter to the echo service. You can put it in the query string:
outToServer.writeChars("GET /echo.php?message=" + sentence + " HTTP/1.0\n\n");
I also changed the HTTP version and appended an extra \n as pointed out by the comment of Steffen Ullrich:
Also you must add empty line to mark the end of the header. And the line ending must be \r\n not \n. And you should better do a HTTP/1.0 request not HTTP/1.1 since your code is neither able to deal with HTTP keep-alive nor with HTTP chunked encoding
However, this is not quite enough. You also need to encode some characters, such as spaces. The URL in the get request must be encoded, as pointed out by #zapl in a comment.
I also recommend to test your echo service first using simple telnet:
telnet localhost 8000
There, you can type your message, "GET /echo.php?message=something" and verify it works. Once you find something that works as intended, you can update the Java code accordingly.
I have the following code to perform a GET request on the following URL:
http://rt.hnnnglmbrg.de/server.php/someReferenceNumber
However, here is my output from Logcat:
java.io.FileNotFoundException: http://rt.hnnnglmbrg.de/server.php/6
Why does it return 404 when the URL is clearly valid?
Here is my connect code:
/**
* Performs an HTTP GET request that returns base64 data from the server
*
* #param ref
* The Accident's reference
* #return The base64 data from the server.
*/
public static String performGet(String ref) {
String returnRef = null;
try {
URL url = new URL(SERVER_URL + "/" + ref);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
returnRef = builder.toString();
} catch (IOException e) {
e.printStackTrace();
}
return returnRef;
}
When you request the URL, it actually return HTTP code 404 which mean not found. If you have control to the PHP script, set the header to 200 to indicate file is found.
You are getting a 404, as said above. To avoid an exception, try something like this:
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.connect () ;
int code = con.getResponseCode() ;
if (code == HttpURLConnection.HTTP_NOT_FOUND)
{
// Handle error
}
else
{
BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
// etc...
}
Never trust what you see in your browser. Always try to mimic your request using something like curl, and you'll clearly see that you're getting an HTTP 404 response code.
java.net will translate the HTTP 404 code to a FileNotFoundException
curl -v http://rt.hnnnglmbrg.de/server.php/4
* About to connect() to rt.hnnnglmbrg.de port 80 (#0)
* Trying 217.160.115.112... connected
* Connected to rt.hnnnglmbrg.de (217.160.115.112) port 80 (#0)
> GET /server.php/4 HTTP/1.1
> User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5
> Host: rt.hnnnglmbrg.de
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Date: Mon, 11 Jun 2012 07:34:55 GMT
< Server: Apache
< X-Powered-By: PHP/5.2.17
< Transfer-Encoding: chunked
< Content-Type: text/html
<
* Connection #0 to host rt.hnnnglmbrg.de left intact
* Closing connection #0
0
From the javadocs at http://docs.oracle.com/javase/6/docs/api/java/net/HttpURLConnection.html
Returns the error stream if the connection failed but the server sent useful data nonetheless. The typical example is when an HTTP server responds with a 404, which will cause a FileNotFoundException to be thrown in connect, but the server sent an HTML help page with suggestions as to what to do.