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.
Related
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.
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 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 programming a network software with Java, but I have a real problem using my application through a "true" network.
Let a software be a host, and listening for client connexions.
Here is my Server loop :
public void run() {
while (mServerSocket != null) {
try {
Socket wClient = mServerSocket.accept();
System.out.println("Client connecté");
wClient.setSoTimeout(50);
wClient.setTcpNoDelay(false);
Client c = new Client(wClient);
synchronized(this) {
mWaitingClients.add(c);
c.start();
}
} catch(Exception ex) {
System.out.println("Server error : " + ex.getMessage());
}
}
}
When a client tried to connect to the server, I use this function :
public Client connect(InetAddress addr, int port) throws Exception {
Socket socket = new Socket(addr, port);
socket.setSoTimeout(50);
socket.setTcpNoDelay(false);
Client c = new Client(socket);
c.start();
return c;
}
And here is the client loop :
public void run() {
try {
ObjectOutputStream out = new ObjectOutputStream(mSocket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(mSocket.getInputStream());
while(mSocket.isConnected() && !mSocket.isClosed()) {
for (int i = 0; i < mOutMessages.size(); i++) {
Message msg = mOutMessages.get(i);
out.writeObject(msg);
}
out.flush();
mOutMessages.clear();
Thread.sleep(50);
out.reset();
while(true) {
try {
Message m = (Message) in.readObject();
mInMessages.add(m);
} catch (Exception e) {
break;
}
}
Thread.sleep(50);
}
} catch(Exception ex) {
try {
mSocket.close();
} catch(Exception exx) {
exx.printStackTrace();
}
ex.printStackTrace();
}
}
Some other parts of the program do Message and put them in the Output list of the Client (mOutMessages).
Some other parts of the program read Message from the mInMessages of the Client.
But something is wrong with this. It works fine locally (server and client on the same computer), but fail or is hazardous (some messages are sent but never received) using two computers (with LAN or through the Internet).
Server ever detect connexions from the clients, send "handshake" messages to the client, but the client never receives them.
I'm more a C programmer than a Java one, and I never had this kind of problem using libc Sockets, so, why my way of doing is wrong ?
Thank you !
Edit :
My Server is created using this function :
public void open(int port) throws Exception {
mServerSocket = new ServerSocket(port);
start(); // Call the run mentionned above.
}
Edit :
Here is my solution, maybe it's not perfect but it works !
public void run() {
try {
BufferedOutputStream buf_out = new BufferedOutputStream(
mSocket.getOutputStream()
);
BufferedInputStream buf_in = new BufferedInputStream(
mSocket.getInputStream()
);
ObjectOutputStream out = new ObjectOutputStream(buf_out);
out.flush();
ObjectInputStream in = new ObjectInputStream(buf_in);
while(mSocket.isConnected() && !mSocket.isClosed()) {
for (int i = 0; i < mOutMessages.size(); i++) {
Message msg = mOutMessages.get(i);
out.writeObject(msg);
out.flush();
}
mOutMessages.clear();
out.reset();
while(true) {
try {
Message m = (Message) in.readObject();
mInMessages.add(m);
} catch (Exception e) {
break;
}
}
}
} catch(Exception ex) {
try {
mSocket.close();
} catch(Exception exx) {
exx.printStackTrace();
}
ex.printStackTrace();
}
If I understand right, both client and server use the run method. If both client and server happen to write sufficiently large messages (not fitting in involved buffers) at the same time then you get a deadlock because neither partner advances to reading (which would drain full buffers). Due to network delays, this might only happen in the non-local scenario, i.e. there may be enough time to pile up enough messages in the mOutMessages buffer.
Note that documentation of Socket.setSoTimeout (which you used) only says that it affects read()s. (For example, in my JDK, ObjectOutputStream seems to use a BlockDataOutputStream with a buffer size of 1024 bytes).
I recommend to either use a separate thread for reading/writing or (if you know the maximum messages size) use a sufficiently large buffer (by wrapping the SocketOutputStream in a BufferedOutputStream). If you opt for larger buffers, you may also want to write one message at a time (and try to read messages after each).
I am using the following code to read messages from a server:
Socket socket;
try {
socket = new Socket(InetAddress.getByName("url.com"), 8080);
is = new DataInputStream(socket.getInputStream());
os = new DataOutputStream(socket.getOutputStream());
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
JOptionPane.showMessageDialog(rootPane,
"Could not establish network connection to the server." + " \nPlease check your internet connection and restart the application.",
"Unable to connect",
JOptionPane.INFORMATION_MESSAGE);
WindowEvent wev = new WindowEvent(this, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev);
setVisible(false);
dispose();
System.exit(0);
}
// Start thread to listen for messages from the server
new ListenFromServer().start();
/*
* Thread class to listen for message from the server
*/
class ListenFromServer extends Thread {
public void run() {
BufferedReader in = new BufferedReader(new InputStreamReader(is));
while (true) {
try {
String tmpMsg = in .readLine().replaceAll("\\r\\n|\\r|\\n", "");
JSONObject json = new JSONObject(tmpMsg);
if (json.get("type").toString().contains("preview")) {
System.out.println("PREVIEW: " + json.get("msg").toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
How can i detect if the connection drops? For example if the server crashes?
Please do not use DataInputStream or DataOutputStream for text. You don't need them and they add confusion.
To detect a server has gone you need to send a piece of data and get a response. If you don't with a certain time, the connection or service is lost.