I'm trying to implement a simple server using Java sockets. The server should echo back the HTTP Request message that the client sends. Thus if I enter http://localhost:8888 in to my browser, I expect to see the HTTP Request message that I sent as plain text in the web page. The code seems to do what I expect it to do, as the browser does display a http message which is the same as what is printed out in cmd when I run the program.
There are some parts of my code I wonder about though, like having:
out.writeBytes("HTTP/1.0 200 OK\r\n"); out.writeBytes("\r\n");
before my data. Is this enough to be a valid HTTP response?
Is there anything else in my code that doesn't seem to make sense, or could be improved?
Here is the full program which is executed in cmd by "java HTTPEcho 8888" for example, and checked by entering localhost:8888 in your browser, and whatever is printed in cmd should be the same as in the browser.
import java.net.*;
import java.io.*;
public class HTTPEcho {
public static void main( String[] args) throws IOException {
if (args.length != 1) {
System.err.println("Usage: java HTTPEcho <port number>");
System.exit(1);
}
int port = Integer.parseInt(args[0]);
try (
ServerSocket welcomeSocket = new ServerSocket(port);
Socket connectionSocket = welcomeSocket.accept();
DataOutputStream out = new DataOutputStream(connectionSocket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
){
// echo back http request message as response to web browser client
out.writeBytes("HTTP/1.0 200 OK\r\n");
out.writeBytes("\r\n");
String s;
while ((s = in.readLine()) != null){
System.out.println(s);
out.writeBytes(s + "\r\n");
if(s.isEmpty()){
break;
}
}
out.close();
in.close();
connectionSocket.close();
} catch (IOException e) {
System.out.println("Exception caught when trying to listen on port "
+ port + " or listening for a connection");
System.out.println(e.getMessage());
}
}
}
Related
I have a larger block of Java code, but the important lines are these:
public static String tcp(String hostName, Number port, Number connectionTimeOutMs, Number readTimeOutMs, String message) {
String errmsg = "";
try (
Socket socket = new Socket();
) {
Inet4Address address = (Inet4Address) Inet4Address.getByName(hostName);
System.out.println("IP address:" + address.getHostAddress());
socket.connect(new InetSocketAddress(address, port.intValue()), connectionTimeOutMs.intValue());
socket.setSoTimeout(readTimeOutMs.intValue());
When I supply an IP address in the form "45.79.112.203" or "tcpbin.com", the code gives a SocketTimeoutException.
In the latter case, the line
System.out.println("IP address:" + address.getHostAddress());
gives the correct IP address, so the hostname is resolved correctly; it matches what ping tcpbin.com returns.
I want to be able to call the function with either an IPv4 address (in String format) or a hostname.
What am I doing wrong? Why does the socket fail to establish a connection, even with a high timeout of 60,000 ms?
Notes:
tcpbin.com is an "echo" server to test socket connections. It is only used as an example and should not be the cause of the problem.
Try the following:
echo "Text to send to TCP" | nc tcpbin.com 4242
You should get back the string that was just sent.
In the tcp() function, I pass in numbers in the form of a Number object, since the Java code gets called from Karate test framework via Java inter-op and JavaScript. JavaScript has the type Number, but no int or double.
===
Update:
Here a simple tcp server TcpServer.java
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) {
System.out.println("Listening on port 4242");
ServerSocket listener = null;
try {
do {
listener = new ServerSocket(4242);
Socket other = listener.accept();
System.out.println(">>> got a new connection from "
+ other.getInetAddress().toString() + " <<<");
other.getOutputStream().write("Blah blah".getBytes());
other.close();
listener.close();
} while (true);
} catch (IOException e) {
e.printStackTrace();
}
}
}
===
Here a test class to test the tcp() function. It is the connect() statement that times out in case host != localhost.
TestTcpFunction.java:
import java.io.*;
import java.net.*;
public class TestTcpFunction {
public static void main(String[] args) {
String sendMessage = "Blah blah";
String host = (args.length==0)
? "localhost"
: "tcpbin.com";
String result = tcp(host, 4242, 30000, 30000, sendMessage);
System.out.println("result = " + result);
System.out.println("matches = " + result.equals(sendMessage));
}
public static String tcp(String hostName, Number port, Number connectionTimeOutMs, Number readTimeOutMs, String message) {
String errmsg = "";
try (
Socket socket = new Socket();
) {
Inet4Address address = (Inet4Address) Inet4Address.getByName(hostName);
System.out.println("trying to connect to:" + address.getHostAddress());
socket.connect(new InetSocketAddress(address, port.intValue()), connectionTimeOutMs.intValue()); // <<< times out if not localhost
socket.setSoTimeout(readTimeOutMs.intValue());
try (
PrintWriter out = new PrintWriter(socket.getOutputStream(), true); // autoflush
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
) {
out.print(message);
StringBuilder sb = new StringBuilder();
String line;
boolean addNewline = false;
while ((line = in.readLine()) != null) {
if (addNewline)
sb.append('\n');
sb.append(line);
if (line.lastIndexOf("</response>") >= 0)
break;
addNewline = true;
}
return sb.toString(); // The xml may not be well formed, for instance missing </response>
} finally {}
} catch (UnknownHostException e) {
errmsg = "Unknown host " + hostName;
} catch (SocketTimeoutException e) {
errmsg = "Socket connection timeout (before connection got established)";
} catch (SocketException e) {
errmsg = "Socket error: " + e.getMessage();
} catch (IOException e) {
errmsg = "Couldn't get I/O for the connection to " + hostName;
} catch (Exception e) {
errmsg = "Unknown socket error " + e.getMessage();
}
System.err.println(errmsg);
return "<Error> function tcp (Utils.java): " + errmsg + "</Error>";
}
}
===
Compile both with javac. Then start the server with java TcpServer.
Next run java TestTcpFunction in a different shell, without parameters.
The first time (with local host) it should work correctly.
Then run again, but with any parameter(s), like java TestTcpFunction 1
This time I get a timeout while trying to connect.
The code has been build and tested on my machine.
The client does not time out in connect. A simple output after connect shows that the connection is actually successfully:
socket.connect(new InetSocketAddress(address, port.intValue()), connectionTimeOutMs.intValue()); // <<< times out if not localhost
System.out.println("connected successfully");
Instead the program hangs while reading from the server. With the current code it will wait until the server closes the connection or has send a line with </response>. But the server tcpbin.com:4242 will not do anything like this. It will simply read anything and echo it back. To get a </response> string one actually has to send this string - which is not done.
Because of this the read will time out after a while based on the timeout set with socket.setSoTimeout. The resulting SocketTimeoutException is wrongly interpreted as connection timeout, but it is a read timeout.
Given that the code expects the echoed message to include the string </response> one must add it to the sent message:
String sendMessage = "Blah blah</response>";
This is still not enough though and a tcpdump shows that the message does not even get sent. This is because the expectation, that out.print(message); is affected by the autoflush is simply wrong - see I created a PrintWriter with autoflush on; why isn't it autoflushing?. Thus, one must explicitly flush the writer:
out.print(message);
out.flush();
tcpdump shows that the message is now actually send, but nothing is echoed back. This is because the echo server actually expects to read lines, but no line end was send yet. Adding it actually helps to send the message, get an echoed message back and break out of the loop:
String sendMessage = "Blah blah</response>\n";
And why did it work with localhost? Because the sample server did not actually behave like the echo server at tcpbin.com. It did not read anything but just sent a fixed message back and closed the connection.
This is part of the program that is having trouble.
public void run() {
while(!isStopped) {
try {
socket = server.accept();
System.out.println(socket.getRemoteSocketAddress() + " has connected");
//problem starts
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String request;
while((request = in.readLine()) != null) {
System.out.println(request);
} //problem ends
FileReader f = new FileReader("html/index.html");
BufferedReader br = new BufferedReader(f);
String response;
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
out.write("HTTP/1.1 200 OK\r\n");
out.write("Content-type: text/html\r\n");
out.write("\r\n");
while((response = br.readLine()) != null) {
out.write(response);
}
out.close();
socket.close();
} catch(Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
I created a java web server and it works fine with all the connections. But when the program listens to the request from client and print that request on the console, the program doesn't continue and so it doesn't respond with the HTML file. I tried getting rid of the printing the request part and the program easily sends the HTML but I don't like that because it doesn't print the initial request. How can I make the server properly listen and print client requests and send responses back accordingly and continue like this in a loop? It would be great to show the codes.
So here's the thing, I have a basic java server that sends back to the client what ever it receives from it. The client is written in python. I'm able to make the first connection as in the server sends the client a message confirming the connection. But when I want the client to send the server something is does nothing. I'm not sure if the problem with the client not sending or the server not receiving.
Here's the code for the server:
int portNumber = Integer.parseInt(args[0]);
try (
ServerSocket serverSocket = new ServerSocket(portNumber);
Socket clientSocket = serverSocket.accept();
PrintWriter outs =
new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
) {
String inputLine, outputLine;
outputLine = "Hello socket, I'm server";
outs.println(outputLine);
outs.println("I' connected");
while ((inputLine = in.readLine()) != null) {
outputLine = inputLine;
outs.println(outputLine);
if (outputLine.equals("Bye."))
break;
}
} 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());
}
} }
and here's the client :
import socket
HOST = "localhost"
PORT = 8080
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
print (socket.getaddrinfo(HOST,PORT))
buffer_size = 100
while True :
data = sock.recv(buffer_size)
print ('you recieved :' , data)
test = input('send here\n')
sock.sendall(bytes(test, 'utf-8'))
print ('you sent : ' , test)
In the Python client:
Your prompt contains a \n but the result from input does not? Try adding a \n to test before sending.
I have a java program which accepts a http request from web browser and in response, program sends a text file contents to display in web browser. The program is working fine when I make request from browser which is installed on the same machine in which java code is running but when I make request from some other web browser which is not on the same machine as in which java code running, the program does not get any request.
This is how I make request from my web browser:-
http://localhost:port_number/
This is working fine...
This is how I make request from some other web browser which is not on my machine:
http://my_ip_address:port_number/
This is not working...
And this is my java code:-
while (true) {
ServerSocket serverSocket = null;
Socket clientSocket = null;
try {
serverSocket = new ServerSocket(32768);
clientSocket = serverSocket.accept();
InetAddress ia = clientSocket.getInetAddress();
jTextArea1.append("Connected to : " + ia + "\n");
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
String inputLine, outputLine;
String s = (String) JOptionPane.showInputDialog(this, "Enter File Name : ");
File f = new File(s);
if (f.exists()) {
out.println("http/1.1 200 ok\r");
out.println("Mime version 1.1");
out.println("Content-Type: text/html\r");
out.println("Content-Length: " + f.length() + "\r");
out.println("\r");
BufferedReader d = new BufferedReader(new FileReader(s));
String line = " ", a;
while ((a = d.readLine()) != null) {
line = line + a;
}
out.write(line);
out.flush();
jTextArea1.append("File Delivered.\n");
d.close();
}
out.close();
clientSocket.close();
serverSocket.close();
} catch (IOException e) {
jTextArea1.append("Accept failed.");
System.exit(1);
}
}
This is not related to the code that you've written. You need to make your IP address publicly accessible. Here's is a related thread.
Check that you are indeed listening on 0.0.0.0:32768 and not 127.0.0.1:32768 or any other particulat IP (specially if you are connected to several network). Start a shell and use netstat -ano on Windows and netstat -anp on Unix or Mac.
Check that your firewall allows remote connection to the port 32768
Java code:
package servermonitor;
import java.io.*;
import java.net.*;
public class CommandListener extends Thread
{
public int count = 0;
public void run()
{
try
{
ServerSocket server = new ServerSocket(4444);
while(true)
{
System.out.println("listening");
Socket client = server.accept();
System.out.println("accepted");
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
System.out.println("got reader");
String data = "";
String line;
while((line = in.readLine()) != null)
{
System.out.println("inloop");
data = data + line;
}
System.out.println("RECIEVED DATA: " + data);
in.close();
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
count++;
out.write("gotcha: " + count + "\\n");
out.flush();
}
}
catch(IOException ex)
{
System.out.println(ex.getMessage());
}
}
}
Java console (when I access the following PHP script):
listening
accepted
got reader
PHP code:
<?php
$PORT = 4444; //the port on which we are connecting to the "remote" machine
$HOST = "localhost"; //the ip of the remote machine (in this case it's the same machine)
$sock = socket_create(AF_INET, SOCK_STREAM, 0) //Creating a TCP socket
or die("error: could not create socket\n");
$succ = socket_connect($sock, $HOST, $PORT) //Connecting to to server using that socket
or die("error: could not connect to host\n");
$text = "Hello, Java!\n"; //the text we want to send to the server
socket_write($sock, $text, strlen($text) + 1) //Writing the text to the socket
or die("error: failed to write to socket\n");
$reply = socket_read($sock, 10000) //Reading the reply from socket
or die("error: failed to read from socket\n");
echo $reply;
?>
When I navigate to the PHP page, it loads forever.
Any ideas?
The Java side expects a newline in its input. You're not sending one, so readLine never finishes.
Also, readLine won't return null until the socket is closed or an exception occurs (I/O error for instance). You need to return some data as soon as you've read a line if your protocol works like that.
As it was told, you need to close socket to readLine returns null.