Reading Outbound messages from HTTP Streaming Connection in JAVA - java

I am implementing an integration client which will be connected to an API Gateway and send requests to the gateway. In short, I am the consumer of the API.
Now, the architecture the opposite party has built that I have to open a http streaming connection and read the outbound messages sent by the system.
In case of http streaming connection, it will be automatically closed if kept on idle state for a while so we have to send continuous heart-beat request to the system so that the stream connection shall stay alive.
Now I have following queries:
Do I have to use URLConnection.openConnection to open streaming channel?
How can I keep the stream open by sending requests? Do I have to open a separate thread for achieving this?
What are Outbound messages? Is the term refers to the responses I receive from the API?
How can I test it before getting actual testing setup? is there any dummy test case available on the internet where I can open stream and read data? if yes, please suggest any link?
I have to read JSON Data.
I have been provided with following Example Code for HTTP Streaming
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.invoke.MethodHandles;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import javax.ws.rs.core.HttpHeaders;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
/** * Sample on Java * Open stream and start StreamReader to read stream in separate thread */
/** * Sample of stream processing */
public class StreamReader implements Runnable {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
final private BufferedReader in;
final private boolean toConsole;
final private String serviceName;
private final Crypto crypto;
StreamReader(BufferedReader in, boolean toConsole, String serviceName, Crypto crypto) {
this.in = in;
this.toConsole = toConsole;
this.serviceName = serviceName;
this.crypto = crypto;
}
#Override
public void run() {
String inputLine;
try {
stop:
while (!Thread.currentThread().isInterrupted()) {
try {
while (!StringUtils.isEmpty(inputLine = in.readLine())) {
if ( inputLine.startsWith( serviceName + ":" ) ) {
log.info("Stream message (outgoing from IPS):");
if (toConsole)
System.out.println("Stream message (outgoing from IPS):");
String[] s = inputLine.split(":");
if (s.length >= 2) {
log.debug("Encoded:");
log.debug(inputLine);
log.trace("Decoded:");
String decoded = URLDecoder.decode(s[1], "UTF-8");
log.trace(decoded);
NReply n = Gson.fromJson(decoded, NReply.class);
log.info("Readable:");
log.info(n.o.toString());
if (toConsole) {
System.out.println("Readable:");
System.out.println(n.o.toString());
}
if (s.length > 2) {
int lastSemicolon = inputLine.lastIndexOf(':');
log.debug("Signed data:");
final String signedData = inputLine.substring(0, lastSemicolon);
log.debug(signedData);
log.debug("base64 encoded signature:");
log.debug(s[2]);
try {
//crypto.checkSignSep(signedData, s[2]);
}
catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
else {
log.error("Invalid stream message:");
log.error(inputLine);
if (toConsole) {
System.out.println("Invalid stream message:");
System.out.println(inputLine);
}
}
}
else {
log.debug("View's info:");
log.debug(inputLine);
}
if ("CLOSED".equals(inputLine)) {
Thread.currentThread().interrupt();
break stop;
}
}
Thread.sleep(1000L);
}
catch (InterruptedException e) {
log.error(e.getMessage(), e);
Thread.currentThread().interrupt();
break;
}
catch (Exception e) {
log.error(e.getMessage(), e);
break;
}
}
log.info("polling has been stopped");
}
finally {
try {
in.close();
}
catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
public void openStream(boolean toConsole) throws IOException
{
//final URL stream = new URL (hostName+"/stream");
final URL stream = new URL ("url");
final URLConnection uc = stream.openConnection();
//uc.setRequestProperty(HttpHeaders.COOKIE, "JSESSIONID=" + heartBeat.getSessionId() );
uc.setRequestProperty(HttpHeaders.COOKIE, "JSESSIONID=" + "SessionIDFROMSERVICE" );
final BufferedReader in =new BufferedReader(new InputStreamReader(uc.getInputStream()));
StreamReader reader=new StreamReader(in,toConsole,serviceName,crypto);
Thread thread=new Thread(reader);
thread.setDaemon(true);
thread.start();
}
}
Any sort of help is appreciated.. :).

Related

Server/Multiclient program wont send message to all clients

I'm working on a program involving a multithreaded server, in which I want messages sent by clients to be echoed back to every client currently connected to the server. It doesn't exactly do this. I will send a message from a client to the server, and it will echo back to that same client. Not to the other client. Let's say, with one client I sequentially type "One" then "Two" then "Three". The exchange will be something like this:
Client 1: "One"
Echo from Server ON Client 1's console: "One"
Client 1: "Two"
Echo from Server ON Client 1's console: "Two"
Client 1: "Three"
Echo from Server ON Client 1's console: "Three"
This part does what it should. But absolutely nothing happens on Client 2's console. Let's say the exchange above has already happened. Client 2's screen will still be blank. I will then type something in Client 2, let's say "Test". The server will respond to Client 2 with "One". Let's say I type "Test" again in Client 2. The server will respond with "Two". You get the idea. I'm not sure why it's doing this. I have three files involved, The Client, The Server, and one meant to manage connections between them.
EDIT: I THINK I KNOW THE PROBLEM! On line 43 in client, the console expects some user input before it will proceed. Which I THINK is why when the first client sends user input, it gets a correct reply, but the second one doesn't: because the second client didn't enter anything in the console, and it's still waiting for some input in order to proceed. Any ideas on how to work around this?
Client:
package client;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Client {
//The socket for the client
Socket sock;
//The stream to read incoming data
DataInputStream din;
//The stream to send outgoing data
DataOutputStream dout;
public static void main(String[] args) {
//Create a new client
new Client();
}
public Client() {
try {
//Activate the socket to the host and port
sock = new Socket("localhost", 4444);
//Open the input and output streams
din = new DataInputStream(sock.getInputStream());
dout = new DataOutputStream(sock.getOutputStream());
//Start listening for user input
listenIn();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void listenIn() {
//Monitors the console for user input
Scanner userIn = new Scanner(System.in);
while(true) {
//While there is nothing left to read from the console
while(!userIn.hasNextLine()) {
try {
//Ensures resources aren't constantly being used by listening for input
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//Get line from user input
String input = userIn.nextLine();
//if user exits the client, break the loop and exit the program
if(input.toLowerCase().equals("quit")) {
break;
}
try {
//outputs user input to Server
dout.writeUTF(input);
//Flushes all data out of the data output stream's buffer space
dout.flush();
//While there's nothing to read from the input stream, save resources
while(din.available() == 0) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//When there's incoming data, print it to the console
String reply = din.readUTF();
System.out.println(reply);
} catch (IOException e) {
e.printStackTrace();
break;
}
}
//Close all the I/O streams and sockets, so there aren't memory leaks
try {
din.close();
dout.close();
sock.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Server:
package server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server {
//The server's socket
ServerSocket sSock;
ArrayList<ServerConnection> connections = new ArrayList<ServerConnection>();
boolean run = true;
public static void main(String[] args) {
//Create a new server
new Server();
}
public Server() {
try {
//Initialize the server socket to the correct port
sSock = new ServerSocket(4444);
//While the socket should be open
while(run) {
//Initialize the client socket to the correct port
Socket sock = sSock.accept();
//Create a new server connection object between the client socket and the server
ServerConnection sConn = new ServerConnection(sock, this);
//Start the thread
sConn.start();
//Add the connection to the arraylist
connections.add(sConn);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Server Connection:
package server;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class ServerConnection extends Thread{
Socket sock;
Server server;
DataInputStream in;
DataOutputStream out;
boolean run = true;
//Create the server connection and use super to run it with Thread's constructor
public ServerConnection(Socket socket, Server server) {
super("ServerConnectionThread");
this.sock = socket;
this.server = server;
}
public void sendOne(String text) {
try {
//Write the text to the output stream
out.writeUTF(text);
//Flush the remaining data out of the stream's buffer space
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
//Send a string to every client
public void sendAll(String text) {
/*Iterate through all of the server connections in the server
and send the text to every client*/
for(int i = 0; i < server.connections.size(); i++) {
ServerConnection sc = server.connections.get(i);
sc.sendOne(text);
}
}
public void run() {
try {
//Set the input stream to the input from the socket
in = new DataInputStream(sock.getInputStream());
//Set the output stream to write out to the socket
out = new DataOutputStream(sock.getOutputStream());
//While the loop should be running (as determined by a boolean value)
while(run) {
//While there is no incoming data, sleep the thread to save resources
while(in.available() == 0) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//Store the incoming data in a string
String textIn = in.readUTF();
//Send it to all clients
sendAll(textIn);
}
//Close datastreams and socket to prevent memory leaks
in.close();
out.close();
sock.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Like you have done in the server side, you may use a separate thread to take care of incoming data in the client side. That way, the waiting for the user input in the console will not block the incoming data flow.
Here is an idea of how you could implement this.
New ClientConnection:
package client;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
public class ClientConnection extends Thread {
DataInputStream din = null;
public ClientConnection(Socket socket) throws IOException {
this.setName("Client-Thread");
this.din = new DataInputStream(socket.getInputStream());
}
public void run() {
boolean run = true;
while (run) {
// While there's nothing to read from the input stream, save resources
try {
// When there's incoming data, print it to the console
String reply = din.readUTF();
System.out.println(reply);
run = this.isAlive();
} catch (SocketException e) {
System.out.println("Disconnected");
run = false;
} catch (IOException e) {
e.printStackTrace();
}
}
try {
din.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
And here is the reformulated Client:
package client;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Client {
// The socket for the client
Socket sock;
// The stream to send outgoing data
DataOutputStream dout;
public static void main(String[] args) {
// Create a new client
new Client();
}
public Client() {
try {
// Activate the socket to the host and port
sock = new Socket("localhost", 4444);
// Open the input and output streams
dout = new DataOutputStream(sock.getOutputStream());
//Listening for incoming messages
ClientConnection client = new ClientConnection(sock);
client.start();
// Start listening for user input
listenIn();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void listenIn() {
// Monitors the console for user input
Scanner userIn = new Scanner(System.in);
while (true) {
// While there is nothing left to read from the console
while (!userIn.hasNextLine()) {
try {
// Ensures resources aren't constantly being used by listening for input
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Get line from user input
String input = userIn.nextLine();
// if user exits the client, break the loop and exit the program
if (input.toLowerCase().equals("quit")) {
break;
}
try {
// outputs user input to Server
dout.writeUTF(input);
// Flushes all data out of the data output stream's buffer space
dout.flush();
} catch (IOException e) {
e.printStackTrace();
break;
}
}
// Close all the I/O streams and sockets, so there aren't memory leaks
try {
dout.close();
sock.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
On the server side, you may also consider removing the disconnected clients from the list of connections:
public class ServerConnection extends Thread {
...
public void run() {
try {
...
} catch (SocketException e) {
System.out.println("Client disconnected");
server.connections.remove(this);
} catch (IOException e) {
e.printStackTrace();
}
}
}
I hope this helps.

Java TCP client repetitive connections result in EMFILE error

My Java application establishes TCP connection with a server and communicates with it every second by sending and receiving messages. Both server and client are run on the same Mac. In about 15-20 minutes, my server crashes with error "Errno::EMFILE Too many files open". Here is my client code:
package testtcp;
import java.awt.Dimension;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestTCP extends JPanel
{
JFrame frame = new JFrame("Button Demo");
ScheduledExecutorService executorService;
private Socket socket = null;
private DataInputStream input = null;
private DataOutputStream output = null;
private BufferedReader br = null;
private boolean isMapUpdating = false;
public TestTCP()
{
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(300,300));
frame.add(this);
JButton b1 = new JButton("BLACK");
b1.setPreferredSize(new Dimension(150,50));
b1.setFocusPainted(false); // get rid of border around text
add(b1);
b1.addActionListener((java.awt.event.ActionEvent evt) ->
{
startAcarsConnection();
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void startAcarsConnection()
{
start();
}
public void start()
{
System.out.println("THREAD START");
// Default timer rate
int timerRate = 1;
executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(new Runnable()
{
#Override
public void run()
{
// Create new TCP connection if the map is not currently updating
if(isMapUpdating == false)
{
isMapUpdating = true;
communicateWithServer();
}
}
}, 0, timerRate, TimeUnit.SECONDS);
}
public void stop()
{
executorService.shutdown();
}
public void communicateWithServer()
{
// Create a message to the server
String messageToServer = makeMessageToServer();
// Connect to the client and receive the response
String messageFromServer = connectToClient(messageToServer);
SwingUtilities.invokeLater(() ->
{
messageReceived(messageFromServer);
});
}
public String connectToClient(String messageToServer)
{
String data = "";
// Message from the server that should terminate TCP connection
String terminator = "END_IGOCONNECT_DATA";
try
{
// Create socket and streams
socket = new Socket("192.168.1.2", 7767);
input = new DataInputStream( socket.getInputStream());
output = new DataOutputStream( socket.getOutputStream());
//Send message to the server
output.writeBytes(messageToServer);
System.out.println("MESSAGE TO SERVER FROM CONNECT TO CLIENT: "+messageToServer);
//Read Response
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
StringBuilder sb = new StringBuilder();
String s = "";
int value;
// Process the message from the server and add to the StringBuilder
while((value = br.read()) != -1)
{
// converts int to character
char c = (char)value;
sb.append(c);
if(sb.toString().contains(terminator))
{
break;
}
}
// Create the final string
data = sb.toString();
}
catch (UnknownHostException e)
{
System.out.println("Sock:"+e.getMessage());
// Close Connection
cancelConnection();
// Pop-up message that the airport was not found
String message = "Application was not able to establish connection with X-Plane.\n"
+ "Check whether IP Address and Port number were correctly entered in Settings.\n"
+ "Check whether connection is not being blocked by your firewall.";
JOptionPane.showMessageDialog(new JFrame(), message, "TCP Connection Error: UnknownHostException",
JOptionPane.ERROR_MESSAGE);
data = "ERROR";
}
catch (EOFException e)
{
System.out.println("EOF:"+e.getMessage());
// Close Connection
cancelConnection();
// Pop-up message that the airport was not found
String message = "Application was not able to establish connection with X-Plane.\n"
+ "Check whether IP Address and Port number were correctly entered in Settings.\n"
+ "Check whether connection is not being blocked by your firewall.";
JOptionPane.showMessageDialog(new JFrame(), message, "TCP Connection Error: EOFException",
JOptionPane.ERROR_MESSAGE);
data = "ERROR";
}
catch (IOException e)
{
System.out.println("IO:"+e.getMessage());
// Close Connection
cancelConnection();
// Pop-up message that the server was not found
if(!e.getMessage().equals("Socket closed"))
{
String message = "Application was not able to establish connection with X-Plane.\n"
+ "Check whether IP Address and Port number were correctly entered in Settings.\n"
+ "Check whether connection is not being blocked by your firewall.";
JOptionPane.showMessageDialog(new JFrame(), message, "TCP Connection Error: IOException",
JOptionPane.ERROR_MESSAGE);
}
// "Connection reset"
data = "ERROR";
}
finally
{
// TO DO!!! DISABLED FOR NOW!! closeSocketPax();
}
return data;
}
public void cancelConnection()
{
executorService.shutdown();
closeSocketPax();
SwingUtilities.invokeLater(() ->
{
System.out.println("Cancel Connection");
});
}
private void closeSocketPax()
{
try
{
if(socket!=null) { socket.close();}
if(input != null) { input.close();}
if(output != null) { output.close();}
if(br != null) { br.close();}
}
catch (IOException ex)
{
String message = "Error closing socket.";
JOptionPane.showMessageDialog(new JFrame(), message, "TCP Connection Error: IOException",
JOptionPane.ERROR_MESSAGE);
}
socket = null;
input = null;
output = null;
br = null;
}
private String makeMessageToServer()
{
return "MESSAGE TO SERVER";
}
private void messageReceived(String message)
{
System.out.println("MESSAGE RECEIVED: "+message);
isMapUpdating = false;
}
public static void main(String[] args)
{
new TestTCP();
}
}
I have been trying to solve this for almost a month already!
Does anyone see a problem in the code and know how to mitigate the problem? Greatly appreciated!
Each connection you create uses a file descriptor. In any operating system there is a limit to the number of descriptors your process can have. For example, in the Linux environment I'm on the limit is 1024. Different O/S's have different limits but in Unix derived environments like Linux and Mac O/S you can run ulimit -n to see what the limit is.
In your code you do:
socket = new Socket("192.168.1.2", 7767);
in the connectToClient method. Each time you do that and you don't close the socket you use up a file descriptor. Eventually you reach the O/S defined limit and you get, in Mac O/S the Errno::EMFILE error.
You have two choices to fix this. The first is pretty much what you have commented out - close the connection when you're done with it. However, as you indicate in the comments this is occurring very frequently and you don't want to incur the overhead of opening and closing constantly.
That brings us to the second choice - reuse the connection. A socket can send data over and over again if the protocol you're designing handles it. Send the data back and forth over the protocol and reuse the Socket.
A warning though - if your physical connection is somehow severed - for example, you switch from Ethernet to Wi-Fi - your service will still need to deal with possible errors. Your code has most of that but you may want to consider closing and attempting to reconnect when this occurs.

Java TCP Multi-thread issue

My program works fine and many users can connect and send commands to the server.
But when a user spams the server with commands the server blocks out all other clients and the server doesn't receive messages from clients other than the one that spammed.
Why is this?
TCPAccept Connections
package game.server;
import java.io.IOException;
import java.net.Socket;
public class TCPAcceptConnections implements Runnable
{
public static Socket clientSocket = null;;
int clientID = -1;
public void run()
{
while(Main.TCP)
{
try
{
clientSocket = TCPServer.serverSocket.accept();
System.out.println("Client Connected.");
clientID++;
new TCPClientManager(clientSocket, clientID).run();
}
catch (IOException e)
{
System.out.println("Couldn't create client socket.");
System.exit(-1);
}
}
}
}
TCPClientManager:
package game.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class TCPClientManager implements Runnable
{
Socket client;
int clientID;
static PrintWriter out;
static BufferedReader in;
String inputLine, outputLine;
boolean destroy = false;
public TCPClientManager(Socket cs, int id)
{
try
{
client = cs;
clientID = id;
out = new PrintWriter(client.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
} catch(IOException e)
{
e.printStackTrace();
}
}
public void run()
{
System.out.println("Created TCPManager for client.");
String command;
while(!destroy)
{
try
{
if((command = in.readLine()) != null) //If received something
{
System.out.println("Commad received: " + command);
System.out.println(" " + Commands.proccessCommand(command));
System.out.println("Command proccessed");
}
else
{
client.close();
destroy = true;
}
} catch (IOException e)
{
try
{
client.close();
} catch (IOException e1)
{
e1.printStackTrace();
destroy = true;
}
System.out.println("Client lost connection.");
destroy = true;
}
}
System.out.println("TCPManager for client destroyed.");
}
}
Commands:
package game.server;
public class Commands
{
public static String proccessCommand(String command)
{
if(command.equalsIgnoreCase("cp"))
{
System.out.println("Creating player...");
System.out.println(" Retrieved client");
return "Player Created";
}
else
{
return "Unkown command: " + command;
}
}
}
If you get an unknown command, you should log it and close the connection.
But you have a more severe problem. You aren't stopping the client handler when it reads null. So once a client disconnects the read will spin futilely forever. If readLine() returns null you must close the socket and exit the loop. If you get any IOException you must also close the socket.

Java socket client/server

Hi i am trying to get some data about a socket client connecting to a mutltythreaded server process in the same machine. The server thread is triggered correctly and the client ip is retreived ok, but i cant seem to be able to send a string through the connection.
THE CLIENT
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package solverapplet;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.*;
/**
*
* #author me
*/
public class Solverapplet {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Socket s;
try {
s = new Socket("IP", 4445);
System.out.println(s.getPort());
//DataInputStream in = new DataInputStream (s.getInputStream());
BufferedWriter out = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream()));
out.write("gamma");
out.newLine();
out.flush();
} catch (UnknownHostException ex) {
Logger.getLogger(Solverapplet.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Solverapplet.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
THE SERVER THREAD
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package serversideserver;
import java.io.*;
import java.net.*;
import java.security.*;
import java.util.List;
import java.sql.*;
import com.google.gson.Gson;
class doComms implements Runnable {
private Socket server;
private String line,input,ip;
doComms(Socket server, String ip) {
this.server=server;
this.ip=ip;
}
public void run () {
input="";
try {
// Get input from the client
BufferedReader in = new BufferedReader(
new InputStreamReader(server.getInputStream()));
PrintStream out = new PrintStream(server.getOutputStream());
Connection conn = null;
try
{
String userName = "root";
String password = "";
String url = "jdbc:mysql://localhost/test";
Class.forName ("com.mysql.jdbc.Driver").newInstance ();
conn = DriverManager.getConnection (url, userName, password);
System.out.println ("Database connection established");
// create the java statement
Statement st = conn.createStatement();
// ResultSet rs;
while((line = in.readLine()) != null && !line.equals(".")) {
// Now do the magic.
//Data data = new Gson().fromJson(line, Data.class);
System.out.println("LINE: " + line);
input=line;
st.executeUpdate("UPDATE `solvers` SET `online`='1',`ip`='"+ server.getInetAddress().toString().substring(1) +"' WHERE `user`='"+ line +"'");
// input= data.getcmd();
out.println("{\"captcha\":1,\"text\":\"abc\",\"is_correct\":\"true\"}");
}
}
catch (Exception e)
{
System.out.println (e.toString());
}
// Now write to the client
System.out.println("UPDATE `solvers` SET `online`='1',`ip`='"+ server.getInetAddress() +"' WHERE `user`='"+ input +"'");
//out.println("Overall message is:" + input);
server.close();
} catch (IOException ioe) {
System.out.println("IOException on socket listen: " + ioe);
ioe.printStackTrace();
}
}
}
The line sent through is empty.
CONNECTION ESTABLISHED
package serversideserver;
import java.io.*;
import java.net.*;
import java.security.*;
import java.sql.*;
/**
* Title: Sample Server
* Description: This utility will accept input from a socket, posting back to the socket before closing the link.
* It is intended as a template for coders to base servers on. Please report bugs to brad at kieser.net
* Copyright: Copyright (c) 2002
* Company: Kieser.net
* #author B. Kieser
* #version 1.0
*/
public class Serversideserver {
private static int port=4445,portsolver=4445, maxConnections=0;
// Listen for incoming connections and handle them
public static void main(String[] args) {
int i=0;
try{
ServerSocket listener = new ServerSocket(port);
Socket server;
long counter=0;
int counter1=0;
int id=0;
String ip="uninit";
while((i++ < maxConnections) || (maxConnections == 0)){
server = listener.accept();
counter++;
doComms conn_c= new doComms(server,ip);
Thread t = new Thread(conn_c);
t.start();
//System.out.println("counter "+ (counter % id) );
}
} catch (IOException ioe) {
System.out.println("IOException on socket listen: " + ioe);
ioe.printStackTrace();
}
}
}
I looks like you've got a bit of a timing issue. The following is your code with correct timing. Note that I removed code unnecessary to the issue at hand.
Client: It looks like in the client, you were writing to the socket and immediately terminating the application (causing the connection to close). The doComms class was writing back to the client so I've added code to read the response. If, however, you were not expecting a response, you would still want to read in a byte. This will allow you to make sure you got the EOF rather than some data, and it blocks the current thread and keeps the connection alive.
package solverapplet;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.*;
/**
*
* #author you
*/
public class Solverapplet {
/**
* #param args the command line arguments
* #throws IOException
*/
public static void main(String[] args) throws IOException {
Socket s = null;
try {
// make connection
s = new Socket("localhost", 4445);
// define streams
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
// write data
out.write("gamma");
out.newLine();
out.flush();
// read response
String returnData = in.readLine();
System.out.println(returnData);
} catch (UnknownHostException ex) {
Logger.getLogger(Solverapplet.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Solverapplet.class.getName()).log(Level.SEVERE, null, ex);
} finally {
// close connection
s.close();
}
}
}
Server: I've changed the server to allow a maximum number of connections at any given time rather than shutting down after the maximum number of connections has been established. Also, note that I the threads are not daemons. If you want to serve X number clients then shutdown, you need a mechanism to allow the threads to continue executing before shutting down ServerSocket
package serversideserver;
import java.io.*;
import java.net.*;
/**
* Title: Sample Server
* Description: This utility will accept input from a socket, posting back to the socket before closing the link.
* It is intended as a template for coders to base servers on. Please report bugs to brad at kieser.net
* Copyright: Copyright (c) 2002
* Company: Kieser.net
* #author B. Kieser
* #version 1.0
*/
public class Serversideserver {
private static int port =4445;
private static int maxConnections =10;
private static int connections = 0;
synchronized static void connectionClosed() {
connections--;
Serversideserver.class.notify();
}
/**
* The blocking mechanism to only allow <code>maxConnections<code>
* #throws InterruptedException
* thrown if blocking thread is interupted
*/
private synchronized static void nextConnection() throws InterruptedException {
while(connections>=maxConnections) {
Serversideserver.class.wait();
}
}
public static void main(String[] args) throws InterruptedException {
try{
// server socket
ServerSocket listener = new ServerSocket(port);
// socket
Socket socket;
// Keep the server alive
while(true){
// Blocks if we have reached the max
nextConnection();
// Accept connection to client
socket = listener.accept();
// define request service
doComms conn_c= new doComms(socket,socket.getInetAddress().getCanonicalHostName());
Thread t = new Thread(conn_c);
t.setDaemon(false);
// run request service
t.start();
}
} catch (IOException ioe) {
System.out.println("IOException on socket listen: " + ioe);
ioe.printStackTrace();
}
}
}
doComms: Not much has changed with this class... I just cleaned it up a bit and removed unnecessary lines of code.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package serversideserver;
import java.io.*;
import java.net.*;
class doComms implements Runnable {
private Socket socket;
private String ip;
doComms(Socket socket, String ip) {
this.socket = socket;
this.ip = ip;
}
public void run () {
try {
// Define input/output
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream out = new PrintStream(socket.getOutputStream());
// Process requests until the EOF is found
String line;
while((line = in.readLine()) != null && !line.equals(".")) {
// print input
System.out.println("LINE: " + line);
// print process line
System.out.println("UPDATE `solvers` SET `online`='1',`ip`='"+ ip +"' WHERE `user`='"+ line +"'");
// write response
out.println("{\"captcha\":1,\"text\":\"abc\",\"is_correct\":\"true\"}");
}
socket.close();
} catch (IOException ioe) {
System.out.println("IOException on socket listen: " + ioe);
ioe.printStackTrace();
} finally {
Serversideserver.connectionClosed();
}
}
}
Hope this helps :)
Your question is seriously vague, but if you're wondering why the server can't reply to your client, it's because the client never reads from the socket.

Create an Object, pass the Object to another Object's constructor, call wait() on Object, then notify() in Java

I'm trying to handle multiple connections on the same port of my server. I'm doing this by instantiating an Object and passing it into the constructor for another class, which implements Runnable. Then I set up a socket in the Runnable class and call notify() on the passed Object after a Client connects on the port. This should then allow the server to restart its loop, creating another instance of the Runnable class after being notified. However, currently the wait() isnt being reached until after the client is closed. Here are the 3 relevant classes I have:
Server class:
package server;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.HashMap;
public class Server {
public static void main(String[] args){
HashMap<String, PortDummy> portDummies = new HashMap<String, PortDummy>();
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8000);
} catch (IOException e1) {
e1.printStackTrace();
}
for(;;){
Object block = new Object();
PortDummy dummy = new PortDummy(serverSocket, block, portDummies);
System.out.println("Running dummy port...");
dummy.start();
try {
synchronized(block){
System.out.println("Waiting...");
block.wait();
System.out.println("Block notified.");
}
} catch (InterruptedException e) {
System.out.println("Can't be interrupted!");
e.printStackTrace();
}
}
}
}
PortDummy (Runnable) class:
package server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
public class PortDummy extends Thread {
private Object block;
private HashMap<String, PortDummy> portDummies;
private String clientName = null;
ServerSocket serverSocket;
BufferedReader socketIn;
PrintWriter socketOut;
public PortDummy(ServerSocket serverSocket, Object block, HashMap<String, PortDummy> portDummies){
this.block = block;
this.portDummies = portDummies;
this.serverSocket = serverSocket;
}
#Override
public void run() {
try {
System.out.println("Starting dummy port...");
Socket clientSocket = serverSocket.accept();
System.out.println("Connection made.");
synchronized(block){
System.out.print("Notifying...");
block.notify();
System.out.println("...done.");
}
socketIn = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
socketOut = new PrintWriter(clientSocket.getOutputStream(), true);
String inContent;
boolean loggedIn = false;
while((inContent = socketIn.readLine()) != null){
socketOut.println("Server Echo: " + inContent);
if(inContent.startsWith("/exit")){
if(loggedIn){
portDummies.remove(clientName);
System.out.println(clientName + " signed out. Removed from portDummies.");
}
else{
System.out.println("Closing...");
}
}
else if(inContent.startsWith("/register")){
System.out.println("/register accepted");
if(!loggedIn){
if(registerUser(inContent)){
System.out.println("Successfully registered.");
socketOut.println(clientName + " successfully registered.");
loggedIn = true;
}else{
socketOut.print("That user already exists.");
}
}
else{
socketOut.print("Already logged in.");
}
}
else if(inContent.startsWith("/tell")){
if(!loggedIn){
socketOut.println("You need to log in.");
}
else{
String[] parts = inContent.split("\\w");
String[] withoutCommand = new String[parts.length-1];
for(int i = 1; i<parts.length-1; i++){
withoutCommand[i] = parts[i];
}
String[] messageParts = new String[withoutCommand.length-1];
String message = "";
for(int j = 1; j<withoutCommand.length-1; j++){
message += withoutCommand[j] + " ";
}
String recipient = withoutCommand[0];
sendMessage(recipient, message);
}
}
else if(inContent.startsWith("/help")){
socketOut.print("/help ~~~~~~~ List all commands. \n " +
"/register <username> ~~~~~~~ Register a new user with 'username'. \n " +
"/tell <username> <message> ~~~~~~~ Send 'username' text 'message'. \n " +
"/exit ~~~~~~~ Log out.");
}
}
System.out.println("Shutting down client connections...");
socketOut.close();
socketIn.close();
clientSocket.close();
serverSocket.close();
} catch (IOException e) {
System.out.println("IOException!");
e.printStackTrace();
}
}
private boolean registerUser(String text){
System.out.println("Registering user...");
String user = text.substring(10);
if((user != null) && !(portDummies.containsKey(user))){
portDummies.put(user, this);
clientName = user;
System.out.println(user + " registered.");
return true;
}
return false;
}
private void sendMessage(String username, String message){
if(portDummies.containsKey(username)){
PortDummy recip = portDummies.get(username);
recip.getSocketOutput().println(clientName + ": " + message);
}
else{
socketOut.write("User " + username + " doesn't exist.");
}
}
public PrintWriter getSocketOutput(){
return socketOut;
}
}
Client class:
package client;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
import java.io.IOException;
public class Client {
protected String username;
public static void main(String[] args){
try{
Socket serverSocket = new Socket("localhost", 8000);
BufferedReader socketIn = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
PrintWriter socketOut = new PrintWriter(serverSocket.getOutputStream(), true);
Scanner keyboardInputScanner = new Scanner(System.in);
String keyboardInput, serverInput;
System.out.println("Welcome to Chris Volkernick's Server IM Client! \n" +
"Type '/register <username>' to register, '/list' to list connected users," +
"\n or '/tell <username> <message>' to send a user a message. '/help' lists these commands. (Type '/exit' to sign out.)");
while((keyboardInput = keyboardInputScanner.nextLine()) != null){
System.out.println("Input '" + keyboardInput + "' read on client side.");
if(keyboardInput.equals("/exit")){
socketOut.println("/exit");
socketOut.close();
socketIn.close();
serverSocket.close();
}else{
socketOut.println(keyboardInput);
while((serverInput = socketIn.readLine()) != null){
System.out.println(serverInput);
}
}
}
keyboardInputScanner.close();
}catch(IOException e){
System.out.println("IOException!");
e.printStackTrace();
}
}
}
Am I doing something wrong with the wait() and/or notify()?
EDIT: I also tried changing the implements Runnable to extends Thread then changing the .run() in the server to .start(), but that gives me this error:
java.net.BindException: Address already in use: JVM_Bind
at java.net.PlainSocketImpl.socketBind(Native Method)
at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:365)
at java.net.ServerSocket.bind(ServerSocket.java:319)
at java.net.ServerSocket.<init>(ServerSocket.java:185)
at java.net.ServerSocket.<init>(ServerSocket.java:97)
at server.PortDummy.run(PortDummy.java:28)
EDIT 2: It seems to be working the way it should now in terms of starting new threads. However, I'm now running into another problem: After I enter a command on the client side of any given client, I can't enter additional commands. The first command will work fine (minus /exit; haven't quite figured out how that should work yet), just can't do anything after that. For example, I can register (sign in) but after that nothing else. I can go into another instance of Client and list all the current users (works), but again, after that I cannot enter additional commands. Any idea what may be happening to cause this?
The problem is that your child threads are trying to listen on port 8000, but the parent thread is already doing that. What you need to do is pass accept a connection from the original socket and then give it to the child thread. I'm not exactly sure how to do this in Java, but I suspect it's just..
Put this in your main thread:
ServerSocket serverSocket = new ServerSocket(8000);
Socket clientSocket = serverSocket.accept();
And then once you get that, pass clientSocket to your Thread.
That way there's only one socket listening on port 8000, but you can make child threads handle each connection.
When using wait and notify, realize that notifies aren't queued, so if the notify happens before the wait occurs, you will never exit the wait. Therefore you should never perform naked waits, that is there should always be some condition you test to see if you should wait.
sychronized(block) {
while (!available) {
block.wait();
}
}
and
synchronized(block) {
available = true;
block.notifyAll();
}
etc
package so_7775790;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Logger;
/**
* barebones server -- ctl-C to kill it ;)
*/
public class Server implements Runnable {
final static Logger log = Logger.getLogger(Server.class.getSimpleName());
public static void main(String[] args) {
final int port = 8000;
final String tname = "my-server-thread";
final Server server = new Server(port);
try {
Thread tserver = new Thread(server, tname);
tserver.start();
tserver.join();
} catch (Exception e) {
log.severe(e.getMessage());
}
}
// -------------------------------------------------
// server
// -------------------------------------------------
final int port;
public Server(int port) {
this.port = port;
}
public void run() {
try{
final ServerSocket srvsocket = new ServerSocket(port);
log.info(String.format("Server started # %s\n", srvsocket));
while(!Thread.currentThread().isInterrupted()){
Socket newclient = srvsocket.accept();
// spawn thread and hand off new client to handler
new Thread(new ClientHandler(newclient)).start();
}
}
catch (Exception e) {
log.severe(e.getMessage());
}
log.info("server stopped");
}
// -------------------------------------------------
// client handler
// -------------------------------------------------
static class ClientHandler implements Runnable {
final Socket socket;
public ClientHandler(final Socket socket) {
assert socket != null : "serverthread is null";
this.socket = socket;
}
#SuppressWarnings("unused")
#Override final
public void run() {
log.info(String.format("new client # %s\n", socket.getRemoteSocketAddress()));
try {
final InputStream in = socket.getInputStream();
final OutputStream out = socket.getOutputStream();
// NOTE: this is just a stub busy loop!
for(;;) {
/* your protocol impl here .. */
}
} catch (Exception e) {
log.severe(e.getMessage());
}
finally {
try {
socket.close();
}
catch (Exception e) {
log.severe(e.getMessage());
}
}
}
}
}

Categories