I am working on 2 applications (web and standalone apps). I have built functionality into the web app for users to be able to restart certain modules of the standalone app from the web page. The way i accomplish this is using a ServerSocket object that listens on a port that is configured as a parameter in the database. This is a shortened version of the server side that listens for the incoming requests :
try
{
int port = Integer.parseInt(globalParamService.findByName("serviceInterconnectPort").getValue());
ServerSocket serverSocket = new ServerSocket(port);
logEntryService.logInfo(LogEntry.CONNECTIVITY, "Successfully started web client connector on port " + port);
while(running)
{
socket = serverSocket.accept();
logEntryService.logInfo(LogEntry.CONNECTIVITY, "Incoming request from web client");
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String message = br.readLine();
if (message.contains("Restart Web Client Connector"))
{
if (!main.isWebClientConnectorRestarting())
{
main.restartWebClientConnector();
String returnMessage = "Done\n";
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
bw.write(returnMessage);
bw.flush();
os.close();
osw.close();
bw.close();
}
else
{
String returnMessage = "Request cancelled\n";
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
bw.write(returnMessage);
bw.flush();
os.close();
osw.close();
bw.close();
logEntryService.logWarning(LogEntry.CONNECTIVITY, "Web client connector restart request cancelled, restart already in progress");
}
}
is.close();
isr.close();
br.close();
socket.close();
}
}
catch (Exception ex)
{
logEntryService.logError(LogEntry.CONNECTIVITY, "Error processing restart request from web client : " + ex.getMessage());
}
Upon deployment of my 2 apps, it is possible that the users would need to change the port this listener is running on. When they do change it from the web app, i extract the unchanged port before updating it in the DB and send it to the below method :
public void restartWebClientConnector(int oldPort)
{
Thread t = new Thread(() ->
{
try
{
logEntryService.logInfo(LogEntry.CONNECTIVITY, "Connecting to port " + oldPort + " to restart web client connector");
InetAddress address = InetAddress.getByName("localhost");
socket = new Socket(address, oldPort);
logEntryService.logDebug(LogEntry.CONNECTIVITY, "Successfully connected to port " + oldPort);
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
bw.write("Restart Web Client Connector\n");
bw.flush();
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String message = br.readLine();
if (message.compareTo("Done") == 0)
{
logEntryService.logInfo(LogEntry.CONNECTIVITY, "Web client connector restart request acknowledged");
}
else
{
logEntryService.logWarning(LogEntry.CONNECTIVITY, "Web client connector restart request cancelled, restart already in progress");
}
os.close();
osw.close();
bw.close();
is.close();
isr.close();
br.close();
socket.close();
}
catch (IOException | NumberFormatException ex)
{
logEntryService.logError(LogEntry.CONNECTIVITY, "Error sending web client connector restart command : " + ex.getMessage());
}
});
t.start();
}
This method then calls the following code which terminates my listener thread and re initializes it on the new updated port number :
public void restartWebClientConnector()
{
if (!webClientConnectorRestarting)
{
webClientConnectorRestarting = true;
webClientConnector.setRunning(false);
webClientConnectorThread.interrupt();
initWebClientConnector();
logEntryService.logInfo(LogEntry.CONNECTIVITY, "Successfully restarted web client connector");
webClientConnectorRestarting = false;
}
}
private void initWebClientConnector()
{
logEntryService.logInfo(LogEntry.CORE, "Initializing web connector");
try
{
webClientConnector = new WebClientConnector(this, globalParamService, logEntryService);
webClientConnectorThread = new Thread(threads, webClientConnector);
webClientConnectorThread.setName("Web Client Connector Thread");
webClientConnectorThread.start();
}
catch (Exception ex)
{
logEntryService.logError(LogEntry.CORE, "Error initializing messaging process : " + ex.getMessage());
}
}
Everything works great except one thing : the old port number is NOT freed up despite explicitly closing everything i can think of. When doing netstat -a after changing the port from the web client, the old port is still listed in LISTENING status. I can change it several times in a row and it works every time but the ports are not freed up. I have spent quite some time researching this and from what i've read it appears i am doing everything correctly (evidently not!).
Whatever input you guys may have would be helpful.
Cheers!
I would recommend you to use resource try blocks, or at least try-finally blocks to ensure the resources are closed:
int port = Integer.parseInt(globalParamService.findByName("serviceInterconnectPort").getValue());
try (ServerSocket serverSocket = new ServerSocket(port)) {
logEntryService.logInfo(LogEntry.CONNECTIVITY, "Successfully started web client connector on port " + port);
while (running) {
try (Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr)) {
String message = br.readLine();
if (message.contains("Restart Web Client Connector")) {
if (!main.isWebClientConnectorRestarting()) {
main.restartWebClientConnector();
String returnMessage = "Done\n";
try (OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw)) {
bw.write(returnMessage);
bw.flush();
}
} else {
String returnMessage = "Request cancelled\n";
try (OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw)) {
bw.write(returnMessage);
bw.flush();
}
logEntryService.logWarning(LogEntry.CONNECTIVITY, "Web client connector restart request cancelled, restart already in progress");
}
}
}
}
} catch (IOException ex) {
logEntryService.logError(LogEntry.CONNECTIVITY, "Error processing restart request from web client : " + ex.getMessage());
}
I changed my WebClientConnector class' run method (it implements Runnable) to the below code :
#Override
public void run()
{
try
{
initWebClientListener();
}
finally
{
try
{
serverSocket.close();
}
catch (IOException ex1)
{}
}
}
And changed my restart method to call interrupt on it as well as setting the running variable to false. The ServerSocket now closes properly and the port is freed.
Related
I'd like to make a client that sends strings to a server occasionally, for example: when application closed it sends a message to server- sendToServer("Client[" + IP + "]Closed")
I have a problem in my code :
Server :
try{
int port = 25000;
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("Server Started and listening to the port 25000");
//Server is running always. This is done using this while(true) loop
while(true)
{
//Reading the message from the client
socket = serverSocket.accept();
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String received = br.readLine();
System.out.println("Message received from client is "+received);
//Multiplying the number by 2 and forming the return message
String returnMessage;
try
{
returnMessage = "You send : " + received;
}
catch(NumberFormatException e)
{
//Input was not a number. Sending proper message back to client.
returnMessage = "Please send a proper number\n";
}
//Sending the response back to the client.
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
bw.write(returnMessage);
System.out.println("Message sent to the client is "+returnMessage);
bw.flush();
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
try
{
socket.close();
}
catch(Exception e){
}
}
CLIENT :
try {
String host = IP;
int port = Port;
InetAddress address = InetAddress.getByName(host);
socket = new Socket(address, port);
//Send the message to the server
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
String number = "2";
String sendMessage = number + "\n";
bw.write(sendMessage);
bw.flush();
System.out.println("Message sent to the server : "+sendMessage);
//Get the return message from the server
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String message = br.readLine();
System.out.println("Message received from the server : " +message);
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
//Closing the socket
try
{
socket.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
For some reason, i never get the message back from the server to the client :/ whats happening? how can i know or solve this?
I send the request from the client, the server gets that request, process it and generate a response that is send. But the client never reads it.
public class Client {
private static Socket socket;
public static void main(String args[]) {
try {
String host = "localhost";
int port = 13579;
System.out.println("Conecting to : " + host + ":" + port);
InetAddress address = InetAddress.getByName(host);
socket = new Socket(address, port);
//Send the message to the server
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
String sendMessage = "103700635105281047295162150000001418 99900001000000717999000NovoTransactionsBusiness 717 VE000000000054300052810472900000000000099900001 1803\n";
bw.write(sendMessage);
bw.flush();
System.out.println("Message sent to the server : " + sendMessage);
//Get the return message from the server
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
//But i never get the message back
String message = br.readLine();
System.out.println("Message received from the server : " + message);
} catch (Exception exception) {
exception.printStackTrace();
} finally {
//Closing the socket
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
The server is running fine!
public class Server {
private static Socket socket;
public static void main(String[] args) {
try {
int port = 13579;
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("Servidor Iniciado escuchando al puerto " + port);
while (true) {
socket = serverSocket.accept();
String strRequest = new BufferedReader(new InputStreamReader(socket.getInputStream())).readLine();
System.out.println("Request Received: " + strRequest);
String returnMessage;
try {
returnMessage = new NovoTrans().init(strRequest).toString();
} catch (Exception e) {
returnMessage = "Error: " + e.getMessage() + "\n";
}
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write(returnMessage);
System.out.println("Sending Message: " + returnMessage);
bw.flush();
}
} catch (Exception e) {
} finally {
try {
socket.close();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
}
I suggest you to use PrintWriter instead of BufferedWriter. There is no need to call flush after each line and simply use println() method along with auto-flush feature to add a new line as well.
Unlike the PrintStream class, if automatic flushing is enabled it will be done only when one of the println, printf, or format methods is invoked, rather than whenever a newline character happens to be output.
These methods use the platform's own notion of line separator rather than the newline character.
There is no need to append \n in the message itself.
Sample code: (Do the changes in both server and client side classes)
// here true means auto flush when `println()` method is called
PrintWriter bw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true);
bw.println(returnMessage);
There are lot of close_wait connection, when ever a client client sends the message to the server and comes out the TCP FSM stuck in the CLOSE_WAIT STATE
This the Client code,
public class Client1
{
private static Socket socket;
public static void main(String args[])
{
try
{
String host = "localhost";
int port = 25000;
InetAddress address = InetAddress.getByName(host);
socket = new Socket(address, port);
//Send the message to the server
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
String number = "2";
String sendMessage = number + "\n";
bw.write(sendMessage);
bw.flush();
System.out.println("Message sent to the server : "+sendMessage);
//Get the return message from the server
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String message = br.readLine();
System.out.println("Message received from the server : " +message);
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
//Closing the socket
try
{
socket.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
This the Server code which listen to the upcoming connection
public class Server1
{
private static Socket socket;
public static void main(String[] args)
{
try
{
int port = 25000;
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("Server Started and listening to the port 25000");
//Server is running always. This is done using this while(true) loop
while(true)
{
//Reading the message from the client
socket = serverSocket.accept();
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String number = br.readLine();
System.out.println("Message received from client is "+number);
//Multiplying the number by 2 and forming the return message
String returnMessage;
try
{
int numberInIntFormat = Integer.parseInt(number);
int returnValue = numberInIntFormat*2;
returnMessage = String.valueOf(returnValue) + "\n";
}
catch(NumberFormatException e)
{
//Input was not a number. Sending proper message back to client.
returnMessage = "Please send a proper number\n";
}
//Sending the response back to the client.
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
bw.write(returnMessage);
System.out.println("Message sent to the client is "+returnMessage);
bw.flush();
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
try
{
socket.close();
}
catch(Exception e){}
}
}
}
The output TCP FSM
-bash:~$ netstat -an | grep 25000
tcp4 0 0 127.0.0.1.25000 127.0.0.1.56459 CLOSE_WAIT
tcp46 0 0 *.25000 *.* LISTEN
You're closing the accepted socket in the wrong place. It needs to be inside the accept loop.
I have a relatively simple program where I try establish Client Server connection and at the same time I use threads in the client side to allow for multiple connections.
I run the server and then the server invokes the client constructor and passes the port connection to the client and the thread is started on the client side.
The problem I have is that when I run the server side it doesn't want to go beyond the constructor call. It seems to get stuck at the constructor.
Sorry all this sounds a bit confusing
Any thoughts perhaps
this is the server side
ServerMultipleThreads()
{
System.out.println("Starting the server first...");
try
{
ServerSoc = new ServerSocket(7777);
listening = true;
}
catch(Exception e)
{
System.out.println(e.toString());
System.exit(1);
}
System.out.println("The server has started running");
while(listening)
{
try
{
//creating the client socket and starting the new client session
new ClientSession(ServerSoc.accept());
System.out.println("The clientSession was called");
in = new DataInputStream(clientSocket.getInputStream());
BufferedReader is = new BufferedReader(new InputStreamReader(in));
os = new PrintStream(clientSocket.getOutputStream());
while(true)
{
line = is.readLine();
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("myFile,txt")), true);
out.println(line);
}
}
catch(IOException ioe)
{
System.out.println(ioe.toString());
}
}
}
and this is on client side
ClientSession(Socket s)
{
clientSocket = s;
try
{
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
out.println("Welcome");
}
catch(IOException exe)
{
System.out.println(exe.toString());
}
//starting the thread
while(runner == null)
{
runner = new Thread(this);
runner.start();
}
}
public void run()
{
while(runner == Thread.currentThread())
{
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
String stdIn;
try
{
while((stdIn = buf.readLine()) != null)
{
out.println(stdIn);
}
}
catch(IOException exe)
{
exe.toString();
}
try
{
Thread.sleep(10);
}
catch(InterruptedException e){}
}
Kind regards
Arian
That is because ServerSocket.accept() blocks until it receives a client request.
You need to have a client calling the server, something like this:
Socket socket = new Socket(host, port);
InputStream in = socket.getInputStream();
// write some data...
I'm writing a piece of software, and I'm under the restriction of not being able to use socket to connect to a java application using a ServerSocket.
I thought I'd try with an URL connection, since it's possible to define which port to connect to
e.g:
127.0.0.1:62666
I have my server app listening for connections and writing the input out to a jTextArea. When connecting to the server (127.0.0.1:62666) through a browser, it outputs:
GET / HTTP/1.1
GET /favicon.ico HTTP/1.1
I have another app for connecting to the ServerSocket through an URL connection:
try{
URL url = new URL("http://127.0.0.1:62666");
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
connection.connect();
PrintWriter writer = new PrintWriter(connection.getOutputStream());
writer.print("Hello");
System.out.println("should have worked");
writer.flush();
writer.close();
}catch(IOException e){
e.printStackTrace();
}
It prints out the "should have worked" message fyi, but it never writes anything to the jTextArea of the server. The code for the server app looks like this:
try{
ServerSocket serverSock = new ServerSocket(62666);
while(doRun){
Socket sock = serverSock.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
PrintWriter writer = new PrintWriter(sock.getOutputStream());
InfoReader.gui.writeToTextArea(reader.readLine() + " From IP: " + sock.getInetAddress() + "\n");
writer.println("Testing123");
writer.close();
reader.close();
}
}catch(IOException e){
e.printStackTrace();
}
Note: when connecting through the browser it displays the text "Testing123".
So I'm wondering how to do this the way I'm trying or perhaps read the URL that the ServerSocket was accessed through, so I could access it through a URL while passing it arguments (in the URL).
Hope this makes sense :)
Thanks,
Mike.
There is one very good example:
public class SimpleHTTPServer {
public static void main(String args[]) throws IOException {
ServerSocket server = new ServerSocket(8080);
while (true) {
try (Socket socket = server.accept()) {
Date today = new Date();
String httpResponse = "HTTP/1.1 200 OK\r\n\r\n" + today;
socket.getOutputStream().write(httpResponse.getBytes("UTF-8"));
}
}
}
}
Go to http://127.0.0.1:8080/ from browser and you'll get current date.
I can't figure out exactly what's up. There's something funny about that OutputStream. Add a
((HttpURLConnection) connection).getResponseCode();
somewhere after connect() and before close(), and you should see something different, if not what you expect.
Perhaps instead of trying to use HTTP as a hack, you should just go full HTTP. Use HTTP from the client like you already are, and set up an embedded HTTP server on the server. There are several to choose from out there that literally take just a few lines to get running: Grizzly, Simple Framework, or Jetty, for instance.
I think this is what you need to do if you want the client to send a message to the server using a URL connection:
public class Client
{
public Client()
{
try
{
url = new URL("http://127.0.0.1:62666");
URLConnection urlConnection = url.openConnection();
PrintWriter writer = new PrintWriter(urlConnection.getOutputStream());
writer.println("Hello World!");
writer.flush();
writer.close();
}catch(Exception e){e.printStackTrace();}
}
}
Now heres the server:
public class Server implements Runnable
{
public Server()
{
ServerSocket server = new Server(62666);
client = server.accept();
new Thread(this).start();
}
public void run()
{
try
{
String message;
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()))
while((message=reader.readLine())!=null)
{
System.out.println("Message from client: "+message);
}
}catch(Exception e)
{
System.out.println("Client disconnected");
}
}
Socket client;
}
writer.println("Hello");
You're not sending any newline. Also your 'should have worked' trace is in the wrong place. Should be after the flush().
Also you aren't reading the response.
Also the server is only going to display POST ... Or PUT ..., not the line you're sending. So this is never going to work unless you (a) make the server HTTP-conscious or (b) get rid of this insane restriction that you can't use a Socket. Why can't you use a Socket?
EDIT: my version of your code follows:
static class Server implements Runnable
{
public void run()
{
try
{
ServerSocket serverSock = new ServerSocket(62666);
for (;;)
{
Socket sock = serverSock.accept();
System.out.println("From IP: " + sock.getInetAddress());
BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
PrintWriter writer = new PrintWriter(sock.getOutputStream());
String line;
while ((line = reader.readLine()) != null)
{
System.out.println("\t:" + line);
}
writer.println("Testing123");
writer.close();
reader.close();
System.out.println("Server exiting");
serverSock.close();
break;
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
static class Client implements Runnable
{
public void run()
{
try
{
URL url = new URL("http://127.0.0.1:62666");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setDoOutput(true);
// connection.setRequestMethod("POST");
connection.connect();
PrintWriter writer = new PrintWriter(connection.getOutputStream());
writer.println("Hello");
writer.flush();
System.out.println("flushed");
int responseCode = connection.getResponseCode();
writer.close();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
System.out.println("closed");
System.out.println("response code="+responseCode);
String line;
while ((line = reader.readLine()) != null)
System.out.println("client read "+line);
reader.close();
System.out.println("Client exiting");
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
public static void main(String[] args)
{
Thread t = new Thread(new Server());
t.setDaemon(true);
t.start();
new Client().run();
System.out.println("Main exiting");
}