I'm trying to run a simple multithreaded server that fetches a URL and also that allows browser to upload file to sever( GET and POST ) it fetches the webpage with GET I'm having trouble with POST, here is my WebServer I'm using for making upload work. Note: HttpRequest is another class that handles threads
import java.net.*;
import java.io.*;
public class WebServer
{
public WebServer(int port)
{
System.out.println("starting web server on port " + port);
ServerSocket serverSocket = null;
try
{
//create the server
serverSocket = new ServerSocket(port);
}catch(IOException ex)
{
System.out.println("could not open port " + port);
System.exit(1);
}
//loop indefinitely
while(true)
{
try
{
Socket connection = null;
connection = serverSocket.accept();
//accept the connection
//create a new thread, start it and return to the waiting state
HttpRequest request = new HttpRequest(connection);
Thread t = new Thread(request);
t.start();
}catch(IOException ex)
{
//fail if an error occurs
System.out.println("problem accepting connection");
System.exit(1);
}
}
}
public static void main(String[] args)
{
//simple validation for the port number
if(args.length != 1)
{
System.out.println("please specify a port");
System.exit(1);
}
int port = -1;
try
{
port = Integer.parseInt(args[0]);
}catch(NumberFormatException ex)
{
System.out.println("invalid port number");
System.exit(1);
}
WebServer server = new WebServer (port);
}
}
here is the Http implements runnable
import java.net.*;
import java.io.*;
public class HttpRequest implements Runnable
{
private DataInputStream input = null;
private Socket connection;
private static DataOutputStream output = null;
public HttpRequest(Socket connection)
{
this.connection = connection;
}
//required method so this can be used as a thread
public void run()
{
try
{
//try and get the streams
input = new DataInputStream(connection.getInputStream());
output = new DataOutputStream(connection.getOutputStream());
}
catch(IOException ex)
{
System.out.println("could not get input/output streams from connection: " + connection.toString());
return;
}
try
{
StringBuilder response = new StringBuilder("");
String request = input.readLine();
System.out.println("request: " + request);
String[] requestArray = request.split(" ");
//read off and ignore the rest of the input
//added so this can be tested with real browsers
while(input.available() != 0)
{
input.read();
}
if (requestArray.length != 3)
{
//request should be of the format GET /index.html HTTP/1.1, die if a bad request comes in
System.out.println("bad request: " + request);
return;
}else
{
//requested file should be the second entry, remove the leading '/'
File requestedFile = new File(requestArray[1].substring(1));
System.out.println("requested file: " + requestedFile);
//check the requested file exists
if(requestedFile.exists())
{
System.out.println("file found, sending response");
DataInputStream fileInput = new DataInputStream(new FileInputStream(requestedFile));
//output HTTP header, must be followed by two new lines
response.append("HTTP/1.1 200 OK\n\n");
String line = fileInput.readLine();
while(line != null)
{
response.append(line);
line = fileInput.readLine();
}
fileInput.close();
output.writeBytes(response.toString());
output.flush();
output.close();
Logger.writeToLog("Request: " + request + "\r\nResponse: " + response.toString());
}
else
{
System.out.println("file not found, sending 404");
response.append("HTTP/1.1 404 Not Found\n\n");
output.writeBytes(response.toString());
output.flush();
output.close();
}
}
}
catch(IOException ex)
{
System.out.println("cannot read request from: " + connection.toString() + ex.toString());
return;
}
catch(NullPointerException ex)
{
System.out.println("bad request: " + connection.toString());
return;
}
try
{
input.close();
output.close();
connection.close();
}
catch(IOException ex)
{
System.out.println("Can't close connection: " + connection.toString());
return;
}
}
}
Your problem is that your HttpRequest class is not implementing the HTTP protocol properly. For starters, you are assuming that all requests are GET requests, and you are ignoring the header lines that follow the request line.
What you need to do is read the HTTP 1.1 Specification ... thoroughly ... and rewrite your code so that it reads and processes requests, and generates responses according to how the spec says it should be done.
Alternatively, don't waste your time reinventing the wheel (probably incorrectly). Use an existing web container framework, or an existing HTTP protocol stack such as Apache HttpComponents.
Related
I have a situation with a Java Socket Input reader.
I am trying to develop an URCAP for Universal Robots and for this I need to use JAVA.
The situation is as follow:
I connect to the Dashboard server through a socket on IP 127.0.0.1, and port 29999.
After that the server send me a message "Connected: Universal Robots Dashboard Server".
The next step I send the command "play".
Here starts the problem. If I leave it like this everything works.
If I want to read the reply from the server which is "Starting program" then everything is blocked.
I have tried the following:
-read straight from the input stream-no solution
-read from an buffered reader- no solution
-read into an byte array with an while loop-no solution
I have tried all of the solution presented here and again no solution for my case.
I have tried even copying some code from the Socket Test application and again no solution.
This is strange because as mentioned the Socket Test app is working with no issues.
Below is the link from the URCAP documentation:
https://www.universal-robots.com/articles/ur/dashboard-server-cb-series-port-29999/
I do not see any reason to post all the trials code because I have tried everything.
Below is the last variant of code maybe someone has an idea where I try to read from 2 different buffered readers. The numbers 1,2,3 are there just so I can see in the terminal where the code blocks.
In conclusion the question is: How I can read from a JAVA socket 2 times?
Thank you in advance!
public void sendPlay() {
try {
// Create a new Socket Client
Socket sc = new Socket("127.0.0.1", 29999);
if (sc.isConnected()) {
InputStream is = sc.getInputStream();
BufferedInputStream in = new BufferedInputStream(is);
String data = "";
int s = in.read();
data += ""+(char)s;
int len = in.available();
System.out.println("Len got : "+len);
if(len > 0) {
byte[] byteData = new byte[len];
in.read(byteData);
data += new String(byteData);
}
System.out.println(data);
System.out.println("1");
// Create stream for data
DataOutputStream out;
out = new DataOutputStream(sc.getOutputStream());
String command = new String();
command = "play"+"\n";
// Send command
out.write(command.getBytes("US-ASCII"));
out.flush();
System.out.println("2");
InputStream is1 = sc.getInputStream();
BufferedInputStream in1 = new BufferedInputStream(is1);
String data1 = "";
int s1 = in1.read();
data1 += ""+(char)s1;
int len1 = in1.available();
System.out.println("Len got : "+len1);
if(len1 > 0) {
byte[] byteData1 = new byte[len1];
in.read(byteData1);
data1 += new String(byteData1);
}
System.out.println(data1);
System.out.println("3");
// Perform housekeeping
out.close();
sc.close();
}
sc.close();
} catch (IOException e) {
System.out.println(e);
}
}
The problem seems to be that you are opening several input streams to the same socket for reading commands.
You should open one InputStream for reading, one OutputStream for writing, and keep them both open till the end of the connection to your robot.
Then you can wrap those streams into helper classes for your text-line based protocol like Scanner and PrintWriter.
Sample program to put you on track (can't test with your hardware so it might need little tweaks to work):
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class RobotTester implements AutoCloseable {
private Socket clientSocket;
private Scanner inputReader;
private PrintWriter outWriter;
private int incounter;
private int outcounter;
public static void main(String[] args) {
System.out.println("Program started. Connecting to robot");
try (RobotTester robot = new RobotTester("127.0.0.1", 29999)) {
System.out.println("Connected to robot.");
robot.nextInput(); //Read and print robot's welcome message
robot.writeCommand("play"); //Send command
String resp = robot.nextInput(); //Read result
if (resp.toLowerCase().startsWith("fail")) {
throw new Exception("Play command failed: " + resp);
}
System.out.println("Command succeeded!");
} catch (Throwable t) {
t.printStackTrace();
}
}
public RobotTester(String host, int port) throws UnknownHostException, IOException {
clientSocket = new Socket(host, port);
inputReader = new Scanner(clientSocket.getInputStream());
outWriter = new PrintWriter(clientSocket.getOutputStream());
}
public String nextInput() {
String mess = inputReader.nextLine();
System.out.println("< " + (++incounter) + ": " + mess);
return mess;
}
public void writeCommand(String command) {
System.out.println("> " + (++outcounter) + ": " + command);
outWriter.print(command);
outWriter.print('\n');
outWriter.flush();
}
#Override
public void close() throws Exception {
if (inputReader != null) {
inputReader.close();
inputReader = null;
}
if (outWriter != null) {
outWriter.close();
outWriter = null;
}
if (clientSocket != null) {
clientSocket.close();
clientSocket = null;
}
}
}
In addition, you're using 127.0.0.1 as server IP address, which is the loopback on your PC. Unless the interface to your robot works in a very peculiar way, the actual IP you should use is probably not this one.
I'm refering to this part of documentation here:
Setup a static IP-address and subnet mask on PC, so it matches the
robot, e.g.:
PC: IP-addr: 192.168.3.10 Robot: IP-addr: 192.168.3.3
Subnet: 255.255.255.0 Subnet: 255.255.255.0
Edit
If you've got more commands to put, use it like this:
//Inside your actual main class
public static void main(String[] args) {
System.out.println("Program started. Connecting to robot");
try (RobotTester robot = new RobotTester("127.0.0.1", 29999)) {
System.out.println("Connected to robot.");
robot.nextInput(); //Read and print robot's welcome message
robot.writeCommand("play"); //Send command
String resp = robot.nextInput(); //Read result
if (resp.toLowerCase().startsWith("fail")) {
throw new Exception("Play command failed: " + resp);
}
System.out.println("Command succeeded!");
robot.writeCommand("command1"); //Send command
resp = robot.nextInput(); //Read result
//Process result for command1
robot.writeCommand("command2"); //Send command
resp = robot.nextInput(); //Read result
//Process result for command2
//...
} catch (Throwable t) {
t.printStackTrace();
}
}
The latest update is that I have moved all the functions in the same Dialog and just called them straight from there, and is still not working.
I already double check there is just one stream and one writer and reader in the entire project.
JButton btnNewButton_2 = new JButton("START");
btnNewButton_2.setBackground(Color.GREEN);
btnNewButton_2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
RobotTester("127.0.0.1", 29999);
nextInput();
String command="play";
writeCommand(command);
nextInput();
} catch (UnknownHostException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
close();
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} });
public void RobotTester(String host, int port) throws UnknownHostException, IOException {
clientSocket = new Socket(host, port);
inputReader = new Scanner(clientSocket.getInputStream());
outWriter = new PrintWriter(clientSocket.getOutputStream());
}
public String nextInput() {
String mess = inputReader.nextLine();
System.out.println("< " + (++incounter) + ": " + mess);
return mess;
}
public void writeCommand(String command) {
System.out.println("> " + (++outcounter) + ": " + command);
outWriter.print(command);
outWriter.print('\n');
outWriter.flush();
}
public void close() throws Exception {
if (inputReader != null) {
inputReader.close();
inputReader = null;
}
if (outWriter != null) {
outWriter.close();
outWriter = null;
}
if (clientSocket != null) {
clientSocket.close();
clientSocket = null;
}
}
I have found a solution to the issue of reading the from the socket multiple times with a Swing GUI.
public void sendPlay() {
Thread appThread = new Thread() {
public void run() {
try {
RobotTester robot = new RobotTester("127.0.0.1", 29999);
System.out.println("Connected to robot.");
robot.nextInput(); //Read and print robot's welcome message
robot.writeCommand("play"); //Send command
String resp = robot.nextInput(); //Read result
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Finished on " + Thread.currentThread());
}
};
appThread.start();}
It seems that the background socket reading needs to be on a separate thread. This was causing the entire robot to be blocked. The idea was from an forum. It was not mine, but hey, it works.
Thank you very much!
Hi Stackover flow world,
Thought I'd send something over as I haven't shared a question in some time. I've been pretty stumped on the weirdest, possibly simplest question ever, that I've been finding all sorts of different responses online.
Basically, I have a SimpleServer which looks as so:
// A generic server that listens on a port and connects to any clients it
// finds. Made to extend Thread, so that an application can have multiple
// server threads servicing several ports, if necessary.
public class SimpleServer
{
protected int portNo = 8082; // Port to listen to for clients
protected ServerSocket clientConnect;
public SimpleServer(int port) throws IllegalArgumentException {
if (port <= 0)
throw new IllegalArgumentException(
"Bad port number given to SimpleServer constructor.");
// Try making a ServerSocket to the given port
System.out.println("Connecting server socket to port...");
try { clientConnect = new ServerSocket(port); }
catch (IOException e) {
System.out.println("Failed to connect to port " + port);
System.exit(1);
}
// Made the connection, so set the local port number
this.portNo = port;
}
public static void main(String argv[]) {
int port = 8088;
if (argv.length > 0) {
int tmp = port;
try {
tmp = Integer.parseInt(argv[0]);
}
catch (NumberFormatException e) {}
port = tmp;
}
SimpleServer server = new SimpleServer(port);
System.out.println("SimpleServer running on port " + port + "...");
server.listen();
}
public void listen() {
// Listen to port for client connection requests.
try {
System.out.println("Waiting for clients...");
while (true) {
Socket clientReq = clientConnect.accept();
System.out.println("Got a client...");
serviceClient(clientReq);
}
}
catch (IOException e) {
System.out.println("IO exception while listening for clients.");
System.exit(1);
}
}
public void serviceClient(Socket clientConn) {
SimpleCmdInputStream inStream = null;
DataOutputStream outStream = null;
try {
inStream = new SimpleCmdInputStream(clientConn.getInputStream());
outStream = new DataOutputStream(clientConn.getOutputStream());
}
catch (IOException e) {
System.out.println("SimpleServer: Error getting I/O streams.");
}
SimpleCmd cmd = null;
System.out.println("Attempting to read commands...");
while (cmd == null || !(cmd instanceof DoneCmd)) {
try { cmd = inStream.readCommand(); }
catch (IOException e) {
System.out.println("SimpleServer: " + e);
System.exit(1);
}
if (cmd != null) {
String result = cmd.Do();
try { outStream.writeBytes(result); }
catch (IOException e) {
System.out.println("SimpleServer: " + e);
System.exit(1);
}
}
}
}
public synchronized void end() {
System.out.println("Shutting down SimpleServer running on port "
+ portNo);
}
}
Then I have a SimpleClient which looks as so:
public class SimpleClient
{
// Our socket connection to the server
protected Socket serverConn;
// The input command stream from the server
protected SimpleCmdInputStream inStream;
public SimpleClient(String host, int port)
throws IllegalArgumentException {
try {
System.out.println("Trying to connect to " + host + " " + port);
serverConn = new Socket(host, port);
}
catch (UnknownHostException e) {
throw new IllegalArgumentException("Bad host name given.");
}
catch (IOException e) {
System.out.println("SimpleClient: " + e);
System.exit(1);
}
System.out.println("Made server connection.");
}
public static void main(String argv[]) {
if (argv.length < 2) {
System.out.println("Usage: java SimpleClient [host] [port]");
System.exit(1);
}
System.out.println("Getting here");
String host = argv[0];
int port=0;
try {
port = Integer.parseInt(argv[1]);
}
catch (NumberFormatException e) {}
SimpleClient client = new SimpleClient(host, port);
System.out.println("Commands are about to send?");
client.sendCommands();
}
public void sendCommands() {
try {
OutputStreamWriter wout =
new OutputStreamWriter(serverConn.getOutputStream());
BufferedReader rin = new BufferedReader(
new InputStreamReader(serverConn.getInputStream()));
wout.write("what is a man is a good man\n");
wout.flush();
rin.readLine();
System.out.println("getting here yo");
// Send a GET command...
wout.write("GET goodies ");
// ...and receive the results
String result = rin.readLine();
System.out.println(result + "I am here");
System.out.println("Server says: \"" + result + "\"");
// Now try a POST command
wout.write("POST goodies ");
// ...and receive the results
result = rin.readLine();
System.out.println("Server says: \"" + result + "\"");
// All done, tell the server so
wout.write("DONE ");
result = rin.readLine();
System.out.println("Server says: \"" + result + "\"");
}
catch (IOException e) {
System.out.println("SimpleClient: " + e);
System.exit(1);
}
}
public synchronized void end() {
System.out.println("Closing down SimpleClient...");
try { serverConn.close(); }
catch (IOException e) {
System.out.println("SimpleClient: " + e);
System.exit(1);
}
}
}
Connected to the target VM, address: '127.0.0.1:64335', transport: 'socket'
Getting here
Trying to connect to localhost 8088
Made server connection.
Commands are about to send?
Output
Connected to the target VM, address: '127.0.0.1:64335', transport: 'socket'
Getting here
Trying to connect to localhost 8088
Made server connection.
Commands are about to send?
For some reason the client freezes at 'commands are about to send', and for some reason doesn't truly 'write' to the socket when sending these commands to the server.
Any clues, am i missing something, completely off the mark here?
Thanks!
Arsalan
Figured it out, seems like there's so much drama when it comes to all the types of streams, writers, readers, etc. It seems that somehow my samples have used the types of these streams incorrectly, as the clear difference to understand is that streams are for everything that implement Output or Input Stream, and are for essentially for reading or writing binary data.
Readers & writers are a layer above streams for reading and writing text. Readers and writers convert binary data from and to characters using a character encoding.
Basically now do this in my SimpleClient
public class SimpleClient
{
// Our socket connection to the server
protected Socket serverConn;
// The input command stream from the server
protected SimpleCmdInputStream inStream;
public SimpleClient(String host, int port)
throws IllegalArgumentException {
try {
System.out.println("Trying to connect to " + host + " " + port);
serverConn = new Socket(host, port);
}
catch (UnknownHostException e) {
throw new IllegalArgumentException("Bad host name given.");
}
catch (IOException e) {
System.out.println("SimpleClient: " + e);
System.exit(1);
}
System.out.println("Made server connection.");
}
public static void main(String argv[]) {
if (argv.length < 2) {
System.out.println("Usage: java SimpleClient [host] [port]");
System.exit(1);
}
System.out.println("Getting here");
String host = argv[0];
int port=0;
try {
port = Integer.parseInt(argv[1]);
}
catch (NumberFormatException e) {}
SimpleClient client = new SimpleClient(host, port);
client.sendCommands();
}
public void sendCommands() {
try {
DataOutputStream wout =
new DataOutputStream(serverConn.getOutputStream());
DataInputStream rin = new DataInputStream(serverConn.getInputStream());
// Send a GET command...
wout.writeChars("GET goodies ");
// ...and receive the results
String result = rin.readLine();
System.out.println("Server says: \"" + result + "\"");
// Now try a POST command
wout.writeChars("POST goodies ");
// ...and receive the results
result = rin.readLine();
System.out.println("Server says: \"" + result + "\"");
// All done, tell the server so
wout.writeChars("DONE ");
result = rin.readLine();
System.out.println("Server says: \"" + result + "\"");
}
catch (IOException e) {
System.out.println("SimpleClient: " + e);
System.exit(1);
}
}
public synchronized void end() {
System.out.println("Closing down SimpleClient...");
try { serverConn.close(); }
catch (IOException e) {
System.out.println("SimpleClient: " + e);
System.exit(1);
}
}
}
Notice the new type of the output and input streams, rather than writers.
Thanks Arsalan!
This is the class containing the main() method:
public class MultithreadedProxyServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listening = true;
int port = 10000; //default
try {
port = Integer.parseInt(args[0]);
} catch (Exception e) {
//ignore me
System.out.println("gnore");
}
try {
serverSocket = new ServerSocket(port);
System.out.println("Started on: " + port);
} catch (IOException e) {
System.err.println("Could not listen on port: " + args[0]);
System.exit(-1);
}
while (listening) {
new ProxyThread(serverSocket.accept()).start();
}
serverSocket.close();
}
}
And this is the ProxyThread class:
public class ProxyThread extends Thread {
private Socket socket = null;
private static final int BUFFER_SIZE = 32768;
public ProxyThread(Socket socket) {
super("ProxyThread");
this.socket = socket; //initialzed my parent before you initalize me
}
public void run() {
//get input from user
//send request to server
//get response from server
//send response to user
System.out.println("run");
try {
DataOutputStream out =
new DataOutputStream(socket.getOutputStream());
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String inputLine, outputLine;
int cnt = 0;
String urlToCall = "";
///////////////////////////////////
//begin get request from client
while ((inputLine = in.readLine()) != null) {
try {
StringTokenizer tok = new StringTokenizer(inputLine);
tok.nextToken();
} catch (Exception e) {
System.out.println("break");
break;
}
//parse the first line of the request to find the url
if (cnt == 0) {
String[] tokens = inputLine.split(" ");
urlToCall = tokens[1];
//can redirect this to output log
System.out.println("Request for : " + urlToCall);
}
cnt++;
}
//end get request from client
///////////////////////////////////
BufferedReader rd = null;
try {
//System.out.println("sending request
//to real server for url: "
// + urlToCall);
///////////////////////////////////
//begin send request to server, get response from server
URL url = new URL(urlToCall);
URLConnection conn = url.openConnection();
conn.setDoInput(true);
//not doing HTTP posts
conn.setDoOutput(false);
//System.out.println("Type is: "
//+ conn.getContentType());
//System.out.println("content length: "
//+ conn.getContentLength());
//System.out.println("allowed user interaction: "
//+ conn.getAllowUserInteraction());
//System.out.println("content encoding: "
//+ conn.getContentEncoding());
//System.out.println("content type: "
//+ conn.getContentType());
// Get the response
InputStream is = null;
HttpURLConnection huc = (HttpURLConnection)conn;
if (conn.getContentLength() > 0) {
is = conn.getInputStream();
rd = new BufferedReader(new InputStreamReader(is));
}
//end send request to server, get response from server
///////////////////////////////////
///////////////////////////////////
//begin send response to client
byte by[] = new byte[ BUFFER_SIZE ];
int index = is.read( by, 0, BUFFER_SIZE );
while ( index != -1 )
{
out.write( by, 0, index );
index = is.read( by, 0, BUFFER_SIZE );
}
out.flush();
//end send response to client
///////////////////////////////////
} catch (Exception e) {
//can redirect this to error log
System.err.println("Encountered exception: " + e);
//encountered error - just send nothing back, so
//processing can continue
out.writeBytes("");
}
//close out all resources
if (rd != null) {
rd.close();
}
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I have copy-pasted the above code from the internet, however I am having difficulties running it.
To answer the question from the post title, the run() method from ProxyThread class is called by JVM, after the thread has been started new ProxyThread(serverSocket.accept()).start(); and it usually contains the actual work that a thread should performed (in this case, it handles whatever the server socket receives and it accepts a connection from a client).
The moment when JVM calls run() method cannot be controlled by the programmer, but is after the thread has been started.
run() method is never called explicitly by the programmer.
This may be a stupid question, but here goes.
Im writing this chat program, where there is a server, and clients that can connect to it. I want to implement private messaging into the program, but I don't know how to get the clients to directly connect to eachother. For the server, I used a ServerSocket, which runs on a single port. To get that to work, I needed to forward a port to the server. Is there a way to get the clients to wait for connections, without forwarding a port to them?
Thanks
The whole point of TCP/IP is that a single client connects to a predefined port on a server. So yes, you'll also need to have a ServerSocket on the client that's going to accept the direct connection. You'll almost always run into trouble with port forwarding and the like, which is why UPnP was invented one day.
What you are trying to do is 'peer to peer' connectivity, aka P2P, which is always, by its very definition, plagued by firewalling problems. As such it's usually, especially for a chat, easier to use the central server as 'switchboard' server and relay the private messages as well.
I've written not long time ago a template for multiple client - server application, that might help you to solve your problem. The rest of your question was already answerd by #Niels, I think ;)
import java.net.*;
import java.io.*;
class ServeConnection extends Thread {
private Socket socket = null;
private BufferedReader in = null;
private PrintWriter out = null;
public ServeConnection(Socket s) throws IOException {
// init connection with client
socket = s;
try {
in = new BufferedReader(new InputStreamReader(
this.socket.getInputStream()));
out = new PrintWriter(this.socket.getOutputStream(), true);
} catch (IOException e) {
System.err.println("Couldn't get I/O.");
System.exit(1);
}
start();
}
public void run() {
System.out.println("client accepted from: " + socket.getInetAddress()
+ ":" + socket.getPort());
// get commands from client, until is he communicating or until no error
// occurs
String inputLine, outputLine;
try {
while ((inputLine = in.readLine()) != null) {
System.out.println("request: " + inputLine);
outputLine = inputLine;
out.println("I've recived "+outputLine);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("server ending");
out.close();
try {
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Server {
public static void svr_main(int port) throws IOException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
} catch (IOException e) {
System.err.println("Could not listen on port: " + port);
System.exit(1);
}
System.out.println("Server ready");
try {
while (true) {
Socket socket = serverSocket.accept();
try {
new ServeConnection(socket);
} catch (IOException e) {
System.err.println("IO Exception");
}
}
} finally {
serverSocket.close();
}
}
}
class Client {
static Socket echoSocket = null;
static PrintWriter out = null;
static BufferedReader in = null;
public static void cli_main(int port, String servername) throws
IOException {
try {
echoSocket = new Socket(servername, port);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(
echoSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host: " + servername);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for " + servername);
System.exit(1);
}
System.out.println("Client ready!");
while (true) {
inputLine = (in.readLine().toString());
if (inputLine == null) {
System.out.println("Client closing!");
break;
}
// get the input and tokenize it
String[] tokens = inputLine.split(" ");
}
out.close();
in.close();
echoSocket.close();
System.out.println("Client closing");
}
}
public class MyClientServerSnippet{
public static void main(String[] args) throws IOException {
if (args.length == 0) {
System.err.println("Client: java snippet.MyClientServerSnippet<hostname> <port>");
System.err.println("Server: java snippet.MyClientServerSnippet<port>");
System.exit(1);
}
else if (args.length > 1) {
System.out.println("Starting client...\n");
Client client = new Client();
client.cli_main(3049, "127.0.0.1");
} else {
System.out.println("Starting server...\n");
Server server = new Server();
server.svr_main(3049);
}
}
}
How can I parse URL queries with a system like this.
For Example something like get these URL arguments in variables.
http://localhost?format=json&apikey=838439873473kjdhfkhdf
http://tutorials.jenkov.com/java-multithreaded-servers/multithreaded-server.html
I made these files
WorkerRunnable.java
package servers;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.net.Socket;
/**
*/
public class WorkerRunnable implements Runnable{
protected Socket clientSocket = null;
protected String serverText = null;
public WorkerRunnable(Socket clientSocket, String serverText) {
this.clientSocket = clientSocket;
this.serverText = serverText;
}
public void run() {
try {
InputStream input = clientSocket.getInputStream();
OutputStream output = clientSocket.getOutputStream();
long time = System.currentTimeMillis();
output.write(("HTTP/1.1 200 OK\n\nWorkerRunnable: " +
this.serverText + " - " +
time +
"").getBytes());
output.close();
input.close();
System.out.println("Request processed: " + time);
} catch (IOException e) {
//report exception somewhere.
e.printStackTrace();
}
}
}
MultiThreadedServer.java
package servers;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
public class MultiThreadedServer implements Runnable{
protected int serverPort = 8080;
protected ServerSocket serverSocket = null;
protected boolean isStopped = false;
protected Thread runningThread= null;
public MultiThreadedServer(int port){
this.serverPort = port;
}
public void run(){
synchronized(this){
this.runningThread = Thread.currentThread();
}
openServerSocket();
while(! isStopped()){
Socket clientSocket = null;
try {
clientSocket = this.serverSocket.accept();
} catch (IOException e) {
if(isStopped()) {
System.out.println("Server Stopped.") ;
return;
}
throw new RuntimeException(
"Error accepting client connection", e);
}
new Thread(
new WorkerRunnable(
clientSocket, "Multithreaded Server")
).start();
}
System.out.println("Server Stopped.") ;
}
private synchronized boolean isStopped() {
return this.isStopped;
}
public synchronized void stop(){
this.isStopped = true;
try {
this.serverSocket.close();
} catch (IOException e) {
throw new RuntimeException("Error closing server", e);
}
}
private void openServerSocket() {
try {
this.serverSocket = new ServerSocket(this.serverPort);
} catch (IOException e) {
throw new RuntimeException("Cannot open port 8080", e);
}
}
}
Dispatch.java
package servers;
public class Dispatch {
/**
* #param args
*/
public static void main(String[] args) {
MultiThreadedServer server = new MultiThreadedServer(9000);
new Thread(server).start();
try {
Thread.sleep(20 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Stopping Server");
server.stop();
}
}
You're doing fine so far.
Read the data off of the InputStream (BufferedReader might help) one line at a time.
Read and learn the HTTP Protocol (see Request Message section here: http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol).
The first line that the client sends is going to follow that format: GET /foo.html?x=y&a=b HTTP/1.1 followed by \n\n that's the Method, URL (with query parameters) and Protocol. Split that line (on the spaces...) and then break the URL up according to the specs.
Everything you need can be found in the String class for parsing the data.
You have forgotten to read what the clients sends. In http the clients opens the connection and than sends the request and waits for the server to reply.
To read the request you have two options. Use a BufferedReader or read it byte by byte.
The BufferedReader is easier. You get a String for every line and can easily split it or replace characters, or whatever ;)
Reading every byte is a little bit faster, but it will only be relevant if you need to serve a huge amount of request per seconds. Than this can really make a difference. I just put this information just so you know ;)
I have included the necessary part for reading in your WorkerRunnable.java.
This reads and prints out the whole client request.
Start your server, open your browser and type: http://127.0.0.1:9000/hello?one=1&two=2&three=3
The First line on the Console will read: GET /hello?one=1&two=2&three=3 HTTP/1.1
Before closing an OutputStream, be sure to call the flush() method. This will force any buffered bytes to be written out. If you don't do it, than there might be some bytes/characters missing and you might be spending a long time looking for the error.
try {
InputStream input = clientSocket.getInputStream();
// Reading line by line with a BufferedReader
java.io.BufferedReader in = new java.io.BufferedReader(
new java.io.InputStreamReader(input));
String line;
while ( !(line=in.readLine()).equals("") ){
System.out.println(line);
}
OutputStream output = clientSocket.getOutputStream();
long time = System.currentTimeMillis();
output.write(("HTTP/1.1 200 OK\n\nWorkerRunnable: " +
this.serverText + " - " +
time +
"").getBytes());
output.flush();
//Flushes this output stream and forces any buffered output bytes to be written out.
output.close();
input.close();
System.out.println("Request processed: " + time);
I don't know exactly what you are doing there. You just told us you need to parse the URL, but maybe a better way is to use the simpleframework (http://www.simpleframework.org)
It is like an embedded HTTP-Server, you can look at the tutorial. It will give you a request object, from there you can easily fetch the parameters in the url.
Technically speaking, you can, but it would leave you with implementing the http protocol on your own.
A much better option would be to use the Java Http Server from Oracle. See the following article for tips http://alistairisrael.wordpress.com/2009/09/02/functional-http-testing-with-sun-java-6-httpserver/