Here's an oversimplified server-client connection in Java that doesn't seem to work. I've made a server that serves properly to a browser. I've also made a http connection that receives data fine from an internet site. However, getting the two to talk to each other seems to be difficult.
I have three classes. Common contains strings and data for the Server and Client classes to use.
Common.java:
import java.io.Serializable;
public class Common {
public static class Data implements Serializable{
private static final long serialVersionUID = 1L;
public String value = null;
public Data(String value) {
this.value = value;
}
}
public static final String PROTOCOL = "http";
public static final String HOST = "localhost";
public static final Integer PORT = 39640;
public static final String PAGE = "/test";
public static final String POST = "POST";
}
Server.java:
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import com.sun.net.httpserver.*;
#SuppressWarnings("restriction")
public class Server {
public static class Handler implements HttpHandler {
#Override
public void handle(HttpExchange exchange) throws IOException {
exchange.getResponseHeaders().add("accept", "*/*");
try {
ObjectInputStream in = new ObjectInputStream(exchange.getRequestBody());
Common.Data data = (Common.Data) in.readObject();
System.out.println(data.value);
exchange.sendResponseHeaders(200, 0);
exchange.close();
} catch(Exception e) {
exchange.sendResponseHeaders(404, 0);
exchange.close();
}
}
}
public static void main(String[] args) {
InetSocketAddress socketAddress = null;
HttpServer server = null;
try {
InetAddress address = InetAddress.getByName(Common.HOST);
socketAddress = new InetSocketAddress(address, Common.PORT);
server = HttpServer.create(socketAddress, 10);
//Add contexts
server.createContext(Common.PAGE, new Handler());
server.start();
} catch(Exception e) {
e.printStackTrace();
}
}
}
Client.java
import java.io.ObjectOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class Client {
public static void main(String[] args) {
try {
URL url = new URL(Common.PROTOCOL, Common.HOST, Common.PORT, Common.PAGE);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(Common.POST);
connection.setDoOutput(true);
connection.connect();
ObjectOutputStream out = new ObjectOutputStream(connection.getOutputStream());
out.writeObject(new Common.Data("Hello world"));
} catch(Exception e) {
e.printStackTrace();
}
}
}
EDIT
I used ss -nt to determine that a connection is in some way occurring, even though no data is being transferred.
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 0 10.0.2.15:46759 108.168.151.6:80
ESTAB 0 0 10.0.2.15:59918 198.252.206.149:443
ESTAB 0 0 127.0.0.1:39030 127.0.0.1:52906
ESTAB 0 0 ::ffff:127.0.0.1:39640 ::ffff:127.0.0.1:35764
ESTAB 0 0 ::ffff:127.0.0.1:35764 ::ffff:127.0.0.1:39640
ESTAB 0 0 ::ffff:127.0.0.1:52906 ::ffff:127.0.0.1:39030
I´ve changed the following points and it works, in a laptop with Windows Vista and JDK 1.6.0_10 :
Commons:
public static final String HOST = "127.0.0.1";
//I´ve changed it to the localhost ip (windows)
Server, in the handle method, writing some chars to output and closing the exchange:
public void handle(final HttpExchange exchange) throws IOException {
exchange.getResponseHeaders().add("accept", "*/*");
try {
final ObjectInputStream in = new ObjectInputStream(exchange.getRequestBody());
final Common.Data data = (Common.Data) in.readObject();
System.out.println(data.value);
exchange.sendResponseHeaders(200, 0);
exchange.getResponseBody().write("Hello!".getBytes());
} catch (final Exception e) {
exchange.sendResponseHeaders(404, 0);
} finally {
exchange.close();
}
In Client class, I read the InputStream from response and print it:
public static void main(final String[] args) {
try {
final URL url = new URL(Common.PROTOCOL, Common.HOST, Common.PORT, Common.PAGE);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(Common.POST);
connection.setDoOutput(true);
connection.connect();
final ObjectOutputStream out = new ObjectOutputStream(connection.getOutputStream());
out.writeObject(new Common.Data("Hello world"));
out.close();
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
connection.disconnect();
} catch (final Exception e) {
e.printStackTrace();
}
}
Nothing happens unless you get the input stream, the error stream, or the response code.
This is because the output is buffered until you do so, so that the Content-length header can be set accurately.
You can bypass that by using chunked or fixed-length transfer mode.
Related
Good evening, I got this server and client here.
WebServer
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class WebServer {
public static void main(String[] args) throws Exception {
HttpServer http = HttpServer.create(new InetSocketAddress(8000), 0);
http.createContext("/test", new MyHandler());
http.setExecutor(null); // creates a default executor
http.start();
//NimServer nimserver = new NimServer(32778);
//nimserver.serve();
}
static class MyHandler implements HttpHandler {
//AtomicInteger atomicInteger = new AtomicInteger(0);
//int theValue = atomicInteger.get();
#Override
public void handle(final HttpExchange t) throws IOException {
final String response;
final String requestMethod = t.getRequestMethod();
if ("GET".equals(requestMethod)) {
// response = String.format("Besuche: %d%n", atomicInteger.addAndGet(1));
}
else if ("POST".equals(requestMethod)) {
// atomicInteger.set(0);
int clientno = new DataInputStream(t.getRequestBody()).readInt();
System.out.println("Send from Client: " + clientno);
int newclientno = clientno + 1;
System.out.println("Increased by Server: " + newclientno);
new DataOutputStream(t.getResponseBody()).writeInt(newclientno);
}
else {
throw new IOException("Unsupported method");
}
//t.sendResponseHeaders(200, response.length());
//final OutputStream os = t.getResponseBody();
//os.write(newclientno);
//os.close();
}
}
}
HttpClient
import java.net.*;
import java.io.*;
public class HttpClient {
public static int clientno = 0;
public static void main(String[] args) throws Exception {
//NimMessage clientnumber = new NimMessage();
//clientnumber.nachricht = "Client No: " + clientno;
URL test = new URL("http://localhost:8000/test");
HttpURLConnection connect = (HttpURLConnection) test.openConnection();
connect.setDoOutput(true);
connect.setDoInput(true);
connect.setRequestMethod("POST");
new DataOutputStream(connect.getOutputStream ()).writeInt(clientno);//send int out
int newclientno = new DataInputStream(connect.getInputStream()).readInt();
System.out.println("Send from Server: " + newclientno);
//BufferedReader in = new BufferedReader(new InputStreamReader(connect.getInputStream()));
//String inputLine;
//System.out.println(clientnumber.createJsonNachricht().toString());
//while ((inputLine = in.readLine()) != null)
// System.out.println(inputLine);
//in.close();
}
}
I was able to send the integer clinetno from the client to the server and increase it at the server. But i can not figure out how to send the new integer newclientno back to the client and display it on the console. Any suggestions what i did wrong?
Okay i found my mistake, i had to add an header in the server to complete the connection. Which i already had but did not noticed it.
t.sendResponseHeaders(200, 0);
I am trying to create a simple server, but am having a problem with trying to accept the connection, specifically the line "connectionSocket = serverSocket.accept();". I also have another class SimpleHttpHandler which handles the connection which is referenced in this code.
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class SimpleHttpServer {
private String rootDirectory;
private int port;
private ServerSocket serverSocket;
private Socket connectionSocket;
public SimpleHttpServer(String rootDirectory, int port) {
this.rootDirectory = rootDirectory;
this.port = port;
}
public void start() {
// Establish the listen socket
try {
serverSocket = new ServerSocket(port);
System.out.println("Server started");
} catch (IOException e1) {
e1.printStackTrace();
}
while (true) {
System.out.println("Inside while");
// Listen for a TCP connection request
try {
connectionSocket = serverSocket.accept();
System.out.println("Client connected");
SimpleHttpHandler simpleHandler = new SimpleHttpHandler(rootDirectory);
simpleHandler.handle(connectionSocket);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SimpleHttpServer server = new SimpleHttpServer(args[0], Integer.parseInt(args[1]));
server.start();
}
}
When I accept a new connection, I need to create a handler to handle it.
The Handler class is:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import org.omg.CORBA.Request;
public class SimpleHttpHandler {
private String rootDirectory;
private StringBuffer readFile;
private FileInputStream fileInputStream;
private File file;
private int b;
public SimpleHttpHandler(String rootDirectory) {
this.rootDirectory = rootDirectory;
}
public void handle(Socket remote) {
try {
// Create in and out streams
BufferedReader in = new BufferedReader(new InputStreamReader(remote.getInputStream()));
PrintStream out = new PrintStream(remote.getOutputStream());
// HTTP requests resolved here based on the protocol
// Read a string line from client
String line = in.readLine();
// Send a string to client
out.println("Not yet implemented");
// Send an empty line to client
out.println();
// Send a byte to client
out.write(123);
// Read a byte from file
file = this.requestFile(rootDirectory, line);
fileInputStream = new FileInputStream(file);
b = fileInputStream.read(); // it returns -1 at end of file
// Read the file
BufferedReader fileReader = new BufferedReader(new FileReader(file));
readFile = null;
while(fileReader.readLine() != null) {
readFile.append(fileReader);
}
if(!file.equals(null)) {
responseMessage(readFile.toString());
} else {
errorMessage();
}
// Close the remote socket and r/w objects
in.close();
out.close();
remote.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private void errorMessage() {
System.out.println(readFile);
System.out.println("HTTP/1.0 500 Internal Server Error");
System.out.println();
System.out.println("^_^ Internal Server Error!");
;
}
private void responseMessage(String string) {
System.out.println("HTTP/1.0 200 OK");
System.out.println();
System.out.println("Hello World!");
}
public File requestFile(String rootDirectory, String path) {
// Construct a full path by connecting <rootDirectory> and requested relative path
File file = new File(rootDirectory, path);
// If it is a directory
// Then load the file index.html
if (file.isDirectory()) {
file = new File(file, "index.html");
}
// If the file exists, the file object is returned
// Otherwise null is returned
if (file.exists()) {
return file;
} else {
return null;
}
}
}
Goal:
My goal with this code is to create a simple web server that can handle multiple clients, and that will respond with the html to say "hi" when the client requests it.
Code:
Here's test number one. It only can handle one client once:
import java.net.*;
import java.io.*;
public class Webserver1 {
public static void main(String[] args) {
ServerSocket ss;
Socket s;
try {
//set up connection
ss = new ServerSocket(80);
s = ss.accept();
} catch (Exception e) {
System.out.println(e.getMessage());
return;
}
try (
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
DataOutputStream out = new DataOutputStream (s.getOutputStream());
) {
String inline = in.readLine();
//http request
if (inline.startsWith("GET")) {
//return http
out.writeBytes("<!doctype html><html><body><p>hi</p></body></html>");
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
Here's test number two. It is meant to handle multiple clients:
import java.net.*;
import java.io.*;
public class Webserver2 {
//class to handle connections
public static class server {
ServerSocket ss;
Socket s[] = new Socket[maxn];
public server () {
try {
ss = new ServerSocket(80);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public InputStream getis(int num) throws Exception {
return s[num].getInputStream();
}
public OutputStream getos(int num) throws Exception {
return s[num].getOutputStream();
}
public void close() throws Exception {
for (int i = 0; i < numc; i++) {
s[i].close();
}
}
public void newc () throws Exception {
s[numc + 1] = ss.accept();
}
}
static int numc = 0;
static final int maxn = 100;
static server se = new server();
public static void main(String[] args) {
try {
while (numc < 6) {
//set up connection, and start new thread
se.newc();
numc++;
System.out.println("0");
(new Client()).start();
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static class Client extends Thread {
public void run() {
try(
BufferedReader in = new BufferedReader(new InputStreamReader(se.getis(numc)));
DataOutputStream out = new DataOutputStream (se.getos(numc));
) {
String inline;
while(true) {
inline = in.readLine();
//wait for http request
if (inline.startsWith("GET")) {
System.out.println("1");
//respond with header, and html
out.writeBytes("HTTP/1.1 200 OK\r\n");
out.writeBytes("Connection: close\r\n");
out.writeBytes("Content-Type: text/html\r\n\r\n");
out.writeBytes("<!doctype html><html><body><p>hi</p></body></html>");
out.flush();
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
}
Problems:
On my computer, if I run the first example, and on my browser I type: "http://192.168.1.xxx", I get a simple "hi". However, on the second one if I try the same thing it simply doesn't work. But if in the command prompt I type: telnet 192.168.1.xxx 80, then type GET it sends back the html. Also, if I replace the DataOutputStream with a PrintWriter, it doesn't even send it to the telnet. However, I know it tries because the program prints "0" every time a connection is made, and "1" every time it prints something.
Questions:
What is the problem that prevents the browser from viewing the html?
Does it have to do with the html itself, the way I set up my connection, or the DataOutputStream?
How can I fix this?
Don't use port 80, use some other random port greater than 6000. And if you didn't close your first program properly, port 80 is still used by that program.
I used a Http server program that is similar to this. The server also creates multiple threads for each connections, so the number of clients in not limited to 100.
` public class MultiThreadServer implements Runnable {
Socket csocket;
static int portno;
static String result;
MultiThreadServer(Socket csocket)
{
this.csocket = csocket;
}
public static void main(String args[])
throws Exception
{
portno=Integer.parseInt(args[0]);
ServerSocket srvsock = new ServerSocket(portno);
System.out.println("Listening");
while (true) {
Socket sock = srvsock.accept();
System.out.println("Connected");
new Thread(new MultiThreadServer(sock)).start();
}
}
public void run()
{
String[] inputs=new String[3];
FileInputStream fis=null;
String file=null,status=null,temp=null;
try
{
InputStreamReader ir=new InputStreamReader(csocket.getInputStream());
BufferedReader br= new BufferedReader(ir);
DataOutputStream out = new DataOutputStream(csocket.getOutputStream());
String message=br.readLine();
inputs=message.split(" ");
if(inputs[0].equals("GET"))
{
try{
out.writeBytes("HTTP/1.1 200 OK\r\n");
out.writeBytes("Connection: close\r\n");
out.writeBytes("Content-Type: text/html\r\n\r\n");
out.writeBytes("<!doctype html><html><body><p>hi</p></body> </html>");
}
out.flush();
fis.close();
csocket.close();
}
catch(Exception ex)
{
status="404 File not found";
os.println(status);
}
}`
I am currently working on a project for sending/receiving objects through TCP sockets. I chose to work with the Kryo Serialization framework, since it is one of the most popular frameworks out there. I saw that for Network communication, KryoNet is recommended, but for my own reasons, I chose to use my own TCP Socket framework (mainly because I want custom control of TCP streams and Threads on my project). The problem I encounter is that I have created the following class for Messages:
public class MyMessage {
public HashMap<String, String> _values;
public MyMessage() {
_values = new HashMap<String, String>();
}
}
And on the server side I have the following code for reading input from a TCP Socket:
import java.io.*;
import java.net.*;
public class MyServer {
private ServerSocket _serverSocket;
private Integer _serverPort;
private boolean _killCommand;
public MyServer() {
_serverSocket = null;
_serverPort = -1;
try {
_serverSocket = new ServerSocket(0);
_serverPort = _serverSocket.getLocalPort();
System.out.println("server started on IP: " + _serverSocket.getInetAddress().getHostAddress() + ":" + _serverPort);
} catch (IOException e) {
e.printStackTrace();
}
_killCommand = false;
}
public void runServer() {
Socket _client= null;
while(_killCommand == false) {
try {
_client = _serverSocket.accept();
_out = _client.getOutputStream();
_in = _client.getInputStream();
(new Thread(new ServerThread(_in, _out))).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
the ServerThread class:
import java.io.*;
import java.util.HashMap;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.*;
public class ServerThread implements Runnable {
private InputStream _in;
private OutputStream _out;
private Kryo kryo;
private Input _input;
private Output _output;
public SynEFOthread(InputStream in, OutputStream out) {
_in = in;
_out = out;
kryo = new Kryo();
_output = new Output(_out);
_input = new Input(_in);
}
#Override
public void run() {
MyMessage msg = null;
System.out.println("Thread worker: about to parse input message");
msg = kryo.readObject(_input, MyMessage.class);
}
}
}
On the other side, the client code is the following:
import java.io.*;
import java.net.Socket;
import java.util.*;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.*;
public class MyClient {
public static void main(String[] args) throws Exception {
String server_ip = "";
Integer server_port = -1;
server_ip = args[0];
server_port = Integer.parseInt(args[1]);
Socket serverSocket = new Socket(server_ip, server_port);
OutputStream _out = serverSocket.getOutputStream();
InputStream _in = serverSocket.getInputStream();
Output _output = new Output(_out);
Input _input = new Input(_in);
MyMessage msg = new MyMessage();
msg._values = new HashMap<String, String>();
msg._values.put("TASK_TYPE", "TOPOLOGY");
Kryo kryo = new Kryo();
kryo.writeObject(_output, msg);
Thread.sleep(100);
kryo.writeObject(_output, _msg);
String _ack = kryo.readObject(_input, String.class);
serverSocket.close();
}
}
The problem is that on ServerThread.run() function, the kryo.readObject() call blocks and nothing is done after that. Am I doing something wrong? Am I opening the streams properly for use with the Kryo Serialization Framework?
Register your class with kryo.register(MyMessage.class) both on client and server sides.
Create a test for your serialization/deserialization code, but instead of sockets use ByteArrayOutputStream/ByteArrayInputStream.
Flush! After you write complete message to stream, flush written bytes to network: _output.flush()
I wish to create a router of some sort to redirect HTTP requests from an HTTP client to a servlet (they preform a negotation process. More background: I wish to do an auth from windows to windows server, going throug a redirective Unix web server).
My servlet is on http://localhost:8080
and my redirector is on 8081
So, I wrote this:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Redirect {
/**
* #param args
* #throws IOException
* #throws InterruptedException
*/
public static void main(String[] args) throws IOException, InterruptedException {
ServerSocket ss = new ServerSocket(8081);
Socket s = new Socket("localhost", 8080);
Socket l = ss.accept();
l.setKeepAlive(true);
s.setKeepAlive(true);
OutputStream os = s.getOutputStream();
InputStream is = l.getInputStream();
Thread t1 = new Thread(new MyReader(is, os,"#1"));
t1.start();
InputStream is2 = s.getInputStream();
OutputStream os2 = l.getOutputStream();
Thread t2 = new Thread(new MyReader(is2, os2,"#2"));
t2.start();
}
public static class MyReader implements Runnable {
private InputStream _i;
private OutputStream _o;
private String _id;
public MyReader(InputStream i, OutputStream o, String id) {
_i = i;
_o = o;
_id = id;
}
#Override
public void run() {
try {
int x;
x = _i.read();
while (x != -1) {
System.out.println(_id);
_o.write(x);
_o.flush();
x = _i.read();
}
System.out.println(x);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
It works fine for most servlets! So what's my problem? My servlet is a persistent one http://en.wikipedia.org/wiki/HTTP_persistent_connection, that is it does connection=keep-alive and does a whole back and forth messaging dance.
What am I doing wrong? I thought I could run two MyReader threads and that they will block until new information comes, but instead they keep blocking.
This is my client:
public class Client {
public static void main(String[] args) throws IOException {
URL u = new URL("http://localhost:8081/Abc/Def");
HttpURLConnection huc = (HttpURLConnection)u.openConnection();
huc.setRequestMethod("GET");
huc.setDoOutput(true);
huc.connect();
InputStream is = huc.getInputStream();//The all auth process is done here
//and HttpUrlConnection support it. If I change 8081 to 8080, it works
}
try adding an infinite wait loop after starting t2 thread as shown below
while ( true) {
sleep(1000);
}