Im new to network programming and I am doing a chatprogram in java. I first used DataOutputStream and It worked fine, but I thought it would be more neat if I used Object Streams, enabling me to send user information. The thing is that ObjectOutPutStream does not send everytime for me. In fact it has the regular pattern of sending every third time. Same deal with the server's messages, the client receives them every third time.
Here is some code:
Client side:
public void start() throws IOException{
output = new ObjectOutputStream(socket.getOutputStream());
if (thread == null) {
client = new ChatClientThread(this, socket);
thread = new Thread(this);
thread.start();
}
}
public void sendMessage(String msg){
try {
output.writeObject(new Message(msg));
output.flush();
}catch (IOException ioe) {
System.out.println("Sending error: " + ioe.getMessage());
stop();
}
}
Server side:
public void run() {
System.out.println("Server Thread " + ID + " running.");
while (true) {
try {
if(streamIn.readObject() instanceof Message){
System.out.println((Message)streamIn.readObject());
server.handleMessage(ID, (Message)streamIn.readObject());
}
}catch (IOException ex) {
System.out.println("Listening error: " + ex.getMessage());
server.remove(ID);
} catch (ClassNotFoundException ex) {
System.out.println("Class was not found");
}
}
}
public void open() throws IOException {
streamOut = new ObjectOutputStream(socket.getOutputStream());
streamIn = new ObjectInputStream(socket.getInputStream());
}
Any ideas why this is happening?
I assume your problem is that you read multiple times from ObjectInputStream assuming that all this times you will get same object. But infact you are just losing it and read next one.
Try to rewrite your server code like this:
System.out.println("Server Thread " + ID + " running.");
while (true) {
try {
Object message = streamIn.readObject();
if (message instanceof Message) {
System.out.println((Message) message);
server.handleMessage(ID, (Message) message);
}
} catch (IOException ex) {
System.out.println("Listening error: " + ex.getMessage());
server.remove(ID);
} catch (ClassNotFoundException ex) {
System.out.println("Class was not found");
}
}
Note how the message was only read once per loop and stored in the variable message where it could be tested.
Also I would add else block with logging message which for some reason happens to be not instance of Message. And print actual exceptions with stacktrace in catch blocks.
Related
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!
I need to have multiple client talk to multiple servers and process responses from them.
So far, I have been able to write the server code which binds to multiple clients (spawns a thread for each client) and client connect to multiple servers.
The place where I facing problem is on the client side - I am not able to receive responses from the servers.
The sequence of operations are as below -
Suppose I have 2 servers and 1 client. client connects to both servers, sends them messages, both servers receive it and both send a reply to the client - I am not able to receive this reply.
Server Code -
#Override
public void run() {
try {
// create a serversocket to listen to requests
ServerSocket serverSocket = new ServerSocket(port);
// create n sockets to listen to 5 client
for (int i = 0; i < n; i++) {
Socket socket = serverSocket.accept();
// create a processor thread for each to read and process the incoming Messages
Processor processor = new Processor(socket);
processor.start();
}
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
Processor at server code -
#Override
public void run() {
try {
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());
while (true) {
String str = in.readObject();
System.out.println(message);
out.write("Got your message " + message.toString());
}
} catch (IOException e) {
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (ClassCastException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Processor completed " );
}
Client code -
public static void main(String[] args) throws IOException, InterruptedException {
// make the connections with other nodes
connections = connect();
// connect() creates connections from the client to all servers and stores the socket and out objects in the object called Connections.Code omitted to avoid clutter
// process all the commands
while(!commands.isEmpty()){
for(int i=0 ; i<2; i++){
send(commands.poll() , i);
}
Thread.sleep(500);
}
}
// Sends Message m to the node i
public static synchronized void send(Message m, int i) {
try {
connections.outs[i].writeInt(m.nodeId);
connections.outs[i].writeInt(m.timestamp);
connections.outs[i].writeObject(m.type);
connections.outs[i].writeObject(m.value);
connections.outs[i].flush();
InputStreamReader isr = new InputStreamReader(connections.sockets[i].getInputStream());
final BufferedReader br = new BufferedReader(isr);
new Thread() {
public void run() {
try {
while (true) {
String message = br.readLine();
System.out.println("Message received from the server : " +message);
}
} catch(IOException e) {
e.printStackTrace();
}
}
}.start();
} catch (IOException e) {
e.printStackTrace();
}
}
I am sure I am doing something wrong when listening to the message. Any suggestion no how to receive and process messages from multiple servers would be very helpful.
TIA
I am facing two problems:
1. You did not flush.
out.write("Got your message " + message.toString());
2. In the server you send no \n
The problem is the method readLine
new Thread() {
public void run() {
try {
while (true) {
String message = br.readLine();
System.out.println("Message received from the server : " +message);
}
} catch(IOException e) {
e.printStackTrace();
}
}
}.start();
from Documentation:
Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed.
But the Server neither send a \n nor a \r. Try
out.write("Got your message " + message.toString() + "\n");
I have one client file clientRPC.java and server file serverRPC.java. Both communicate using TCP protocol and use objectinput and output stream to transfer data.
my client file:
public class clientRPC {
public static void main(String args[]) {
Socket s = null;
try {
int serverPort = 8888;
s = new Socket("localhost", serverPort);// server name is local host
//initializing input and output streams object and referencing them to get input and output
ObjectInputStream in = null;
ObjectOutputStream out = null;
out = new ObjectOutputStream(s.getOutputStream());
in = new ObjectInputStream(s.getInputStream());
MathsTutor mt = new MathsTutor();
out.writeObject(mt);
out.flush();
System.out.println("Welcome to Maths Tutor Service. The available maths exercises are:\n"
+ "Addition: Enter 'A' or 'a'\n"
+ "Subtraction: Enter 'S' or 's'\n"
+ "Multiplication: Enter 'M' or 'm'\n"
+ "Division: Enter 'D' or 'd'\n"
+ "Enter 'Q' or 'q' to quit");
//System.out.println();
MathsTutor mt1 = (MathsTutor) in.readObject();
String response = in.readUTF();
System.out.println(response);
} catch (UnknownHostException e) {
System.out.println("Socket:" + e.getMessage());
} catch (EOFException e) {
System.out.println("EOF:" + e.getMessage());
} catch (IOException e) {
System.out.println("readline:" + e.getMessage());
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
} finally {
if (s != null) {
try {
s.close();
} catch (IOException e) {
System.out.println("close:" + e.getMessage());
}
}
}
}
}
and my server file :
public class serverRPC extends Thread {
String request;
String response;
public static void main(String args[]) {
try {
int serverPort = 8888;
ServerSocket listen_socket = new ServerSocket(serverPort);
while (true) {
Socket clientSocket = listen_socket.accept();
Connection c = new Connection(clientSocket);
}
} catch (IOException e) {
System.out.println("Listen socket:" + e.getMessage());
}
public serverRPC(String s) {
request = s;
}
}
class Connection extends Thread {
ObjectInputStream in;
ObjectOutputStream out;
Socket clientSocket;
public Connection(Socket aClientSocket) {
try {
clientSocket = aClientSocket;
in = new ObjectInputStream(clientSocket.getInputStream());
out = new ObjectOutputStream(clientSocket.getOutputStream());
this.start();
} catch (IOException e) {
System.out.println("Connection:" + e.getMessage());
}
}
public void run() {
try {
MathsTutor mt = (MathsTutor) in.readObject();
InetAddress ip = clientSocket.getInetAddress();
System.out.println("The Received Message from Client at address:/" + ip.getHostAddress());
System.out.println("====================================");
MathsTutor mt1 = new MathsTutor();
out.writeObject(mt1);
while(true) {
// Read from input
String command = in.readUTF();
System.out.println(command);
}
//System.out.println();
} catch (EOFException e) {
System.out.println("EOF:" + e.getMessage());
} catch (IOException e) {
System.out.println("readline:" + e.getMessage());
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {/*close failed*/
}
}
}
}
The problem is when I run server and then client on cmd, the client side displays the welcome msg and puts cursor on another line for user input but, I can't type anything, the cursor just blinks... I know this might be simple but it has taken already 3 hours for me and I'm stuck in the same thing.
The cursor marked with red keeps blinking but doesn't let me type anything.
You're writing an object with writeObject() and trying to read it with readUTF(). Illogical.
objects written with writeObject() must be read with readObject().
strings written with writeUTF() must be read with readUTF().
primitives written with writeXXX() must be read with readXXX(), for most values of X.
I want to know if is possible to close the current java app util another has done some task, my code is this:
private static void callJar(String jardir) throws IOException, InterruptedException {
// jardir contains the excecution command
Process p = Runtime.getRuntime().exec(jardir);
synchronized (p) {
// Here I want to wait for p for a signal but not when p has finished
// but waitFor() do the second
p.waitFor();
}
// If the other jar is correctly loaded, close this jar
System.exit(0);
}
The string jardir contains the excecution command that will start the other process that I will be listening, something like this:
jardir = "javaw -jar \\path\\to\\anotherjar.jar"
For now, callJar() opens this process and then close the current until the process that I started has been terminated. In other words, close A until B has been closed.
But what I want to do is to close A until B send a signal (B will continue to exist).
Is there a way to listen for a signal from the process that I started?
After searching for an answer, I finally found a solution, maybe this will work for someone so here is what I did:
Based on this answer and this site, I opted to create a communication between two Java apps using the java.net libraries.
In the process A, I have a method that create a server communication and just waits until it receive a message from process B...
private static boolean listen2ExternalProcess() {
ServerSocket server = null;
Socket serverSocked = null;
String line;
BufferedReader inputReader = null;
try {
server = new ServerSocket(3333);
serverSocked = server.accept();
inputReader = new BufferedReader(
new InputStreamReader(serverSocked.getInputStream()));
while (true) {
line = inputReader.readLine();
log.info("Client says: " + line);
if (line.equals("Kill yourself :D")) {
return true;
}
}
} catch (UnknownHostException e) {
log.error("Don't know about this, " + e);
return false;
} catch (IOException e) {
log.error("Couldn't get IO for the connection, " + e);
return false;
} finally {
try {
if(serverSocked != null) serverSocked.close();
if(inputReader != null) inputReader.close();
} catch (IOException ex) {
log.error("Couldn't get IO for the connection, " + ex);
return false;
}
}
}
this method will return true if the message has been received, then I can proceed to terminate process A.
In the process B, I have a method that just send a message to a socket when I need it...
public static void talk2ExternalProcess() {
Socket socket = null;
BufferedWriter outputWriter = null;
try {
socket = new Socket("localhost", 3333);
outputWriter = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream()));
} catch (UnknownHostException e) {
log.error("Don't know about host: localhost, " + e);
} catch (IOException e) {
log.error("Couldn't get IO for the connection to localhost, " + e);
}
if (socket != null && outputWriter != null) {
try {
outputWriter.write("Kill yourself :D");
} catch (UnknownHostException e) {
log.error("Trying to connect to unkown host: " + e);
} catch (IOException e) {
log.error("IO Exception: " + e);
} finally {
try {
outputWriter.close();
socket.close();
} catch (IOException ex) {
log.error("IO Exception: " + ex);
}
}
} else {
log.warn("null socket or outputwriter");
}
}
finally, I just change the callJar method to something like this:
private static void callJar(String jardir) throws IOException {
Runtime.getRuntime().exec(jardir);
if (listen2ExternalProcess()) {
System.exit(0);
} else {
log.warn("Something went wrong...");
}
}
I would like to find an easier answer, but for now, this works for me.
I'm setting up a comet server that connects to a XMPP server. Here's how it goes down:
A client connects with the comet server and, among other things, a socket connection is opened:
try {
radio = new Socket("server", 5222);
out = new PrintWriter(radio.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(radio.getInputStream()));
} catch (UnknownHostException e) {
System.out.println("Unknown host: "+e);
error = e.toString();
} catch(IOException e) {
System.out.println("IO error: "+e);
error = e.toString();
}
Next, a thread is started, which waits for data from the socket:
public void run() {
System.out.println("Thread started.");
String data;
String error;
Client remote;
Client client;
while(!done) {
data = this.output();
remote = bayeux.getClient(remoteId);
client = bayeux.getClient(clientId);
if(data!=null) {
Map<String, Object> packet = new HashMap<String, Object>();
packet.put("xml", data);
remote.deliver(client, "/radio/from", packet, null);
}
error = this.error();
if(error!=null) {
Map<String, Object> packet = new HashMap<String, Object>();
packet.put("details", error);
remote.deliver(client, "/radio/error", packet, null);
}
/* try {
Thread.sleep(500);
}
catch (InterruptedException e ) {
System.out.println("Interrupted!"); } */
}
try {
in.close();
out.close();
radio.close();
} catch(IOException e) {
System.out.println("Error disconnecting: "+e);
error = e.toString();
}
System.out.println("Thread stopped.");
}
public String output() {
try {
String data = in.readLine();
System.out.println("From: "+data);
if(data==null) {
System.out.println("End of stream!");
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//error = "End of stream.";
//this.disconnect();
}
return data;
} catch (IOException e) {
error = e.toString();
System.out.println("IO error! "+e);
}
return null;
}
Any input received from the client is forwarded to the XMPP server:
public void input(String xml) {
System.out.println("To: "+xml);
out.println(xml);
}
So here's where the problem come in. The client opens the connection and sends the proper XML to the XMPP server to start a stream. in.readLine(); hangs, as it should, until a response is received from the server. As soon as it is received, in.readLine(); begins to return null, over and over again. This shouldn't happen; it should hang until it receives data. It seems unlikely that the server has closed out on me, it hasn't sent the </stream:stream> to signal the end of an XMPP stream. Any ideas on what could be the problem?
Thank you for your help!
Keep in mind that the XMPP connection can and will give you incomplete stanzas, or multiple stanzas in a single read. If your COMET connection expects that what you're passing it is well-formed XML, you will have issues. As well, XMPP is not newline-terminated, so I'm not sure why you expect readLine() to be terribly useful.
Next, are you doing synchronous I/O on two different sockets on the same thread? Sounds like a recipe for a deadlock. If you insist on going down this path (instead of just using BOSH), I'd strongly urge you to use NIO, instead of your sleep hack.