I have a 2 nodes that should always communicate with each other, but they don't seem to talk for more than 1 interaction. After successfully sending and receiving 1 message, they stop.
My code looks like this:
The initiator:
try {
Socket client = new Socket(ip, port);
OutputStream toNode = client.getOutputStream();
DataOutputStream out = new DataOutputStream(toNode);
out.writeUTF("Start:Message");
System.out.println("Sent data");
InputStream fromNode = client.getInputStream();
DataInputStream in = new DataInputStream(fromNode);
if(in.readUTF().equals("Return Message")) {
System.out.println("Received data");
out.writeUTF("Main:Message");
System.out.println("Sent data again");
}
else
System.out.println("Error");
client.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
The responder:
while(true) {
Socket server;
try {
server = s.accept();
DataInputStream in = new DataInputStream(server.getInputStream());
String msg = in.readUTF();
String[] broken_msg = msg.split(":");
if(broken_msg.length > 0)
System.out.println("Looping");
String ret;
if (broken[0].equalsIgnoreCase("Start")) {
ret = "Return Message";
DataOutputStream out = new DataOutputStream(server.getOutputStream());
out.writeUTF(ret);
}
else if (broken[0].equalsIgnoreCase("Main")) {
//Do Useful work
}
} catch (IOException e) {
e.printStackTrace();
}
}
My output looks like this:
Looping
and:
Sent data
Received data
Sent data again
You are looping around the accept() call, accepting new connections, but your actual I/O code only reads one message per connection. You need an inner loop around the readUTF() calls, handling the entire connection until EOFException is thrown. Normally all the I/O for a connection is handled in a separate thread.
In order for programs to do repetitive actions, you would generally use looping of some sort, including for loops, while loops and do-while loops. For something like this where you don't know how many times you'd need to communicate in advance, then you would need to use a while loop, not a for loop.
Having said that, you have no while loops whatsoever inside of your connection code... so without code that would allow continued communication, your program will stop, exactly as you've programmed it to do.
Solution: fix this. Put in while loops where continued communication is needed.
Related
I am attempting a client/server type chat box (using GUI's). I won't get into details of the multi-threading I used in the program since I believe it is not part of the problem (I hope not) and it will be good amount of code to post. Anyways, for both my client and my server I create a socket, and some other stream classes within a try block, and some reason the sockets close after the catch blocks. PS I do NOT call socket.close() method anywhere that could end if early
Server, this is ran into a constructor of one of my class. It breaks down into, my main has the actually server stuff on a different thread, (like my previous post) it is a fix so that the gui can load and run the server stuff without one waiting on the other. Anyways, without all that detail, here is my code
public ChatAppProtocol(Socket sock)
{
super("ChatAppServer");
// this also has a clas var of Socket
this.sock = sock;
try (
PrintWriter output = new PrintWriter(this.sock.getOutputStream(), true);
BufferedReader input = new BufferedReader(new InputStreamReader(this.sock.getInputStream())) ;
)
{
// first stream of a string is the username loging in from client
String name = input.readLine();
// this returns false, so its not closed
System.out.println("closed?: " + this.sock.isClosed());
}
catch (IOException e)
{
e.printStackTrace();
}
// PROBLEM!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// closed after the catch blocks before methods even ends
// p.s. i also plan on using the socket in another method but can't since it closes
System.out.println("closed?: " +this.sock.isClosed());
}
now my client
#FXML
private void login()
{
this.name = this.username.getText().trim();
this.portnum = Integer.parseInt(this.port.getText());
this.name = this.username.getText().trim();
this.ipaddr = this.ip.getText().trim();
try (t
Socket socket = new Socket(this.ipaddr, this.portnum);
PrintWriter output = new PrintWriter(socket.getOutputStream(), true);
)
{
this.sock = socket;
output.println(this.name);
// this returns false, not closed
System.out.println("closed?: " +this.sock.isClosed());
}
catch (UnknownHostException e)
{
System.err.println("Problem at ip: " + this.ipaddr);
System.exit(1);
}
// PROBLEM!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// returns true here, closes before methods end and i cant reuse it
System.out.println("IS IT CLOSED!!!!!! " + this.sock.isClosed());
}
}
so, any reason why both this different class, different files, different project sockets close after try-catch blocks? Can't find answer online, and been on it for a while and I am stuck. I found out about this problem after seeing this on the server side console
java.net.SocketException: Socket is closed
at java.net.Socket.getOutputStream(Socket.java:943)
at chatappserver.ChatAppProtocol.run(ChatAppProtocol.java:62)
Because you're creating socket with the brackets of the try block, it is automatically closed upon exiting the block. Instead, try creating it inside the block itself and it shouldn't be closed:
try {
this.sock = new Socket(this.ipaddr, this.portnum);
PrintWriter output = new PrintWriter(socket.getOutputStream(), true);
output.println(this.name);
} catch (UnknownHostException e) {
System.err.println("Problem at ip: " + this.ipaddr);
System.exit(1);
}
// this.sock should still be open at this point.
Have a read of the Java tutorial on try-with-resources for more information on why you're getting your current behaviour.
You are using try-with-resources, which is roughly an equivalent of:
try
{
this.sock = new Socket(this.ipaddr, this.portnum));
output.println(this.name);
// this returns false, not closed
System.out.println("closed?: " +this.sock.isClosed());
}
catch (UnknownHostException e)
{
System.err.println("Problem at ip: " + this.ipaddr);
System.exit(1);
} finally {
if (this.sock != null)
this.sock.close();
}
Just initialize the socket outside the resources clause of try (...) and it won't get closed
I've created a client-server connection, something like a chat system. Previously I was using a while loop on the client side, and it was waiting to read a message from the console every time (of course server has a while loop as well to serve forever). But now, I'm trying to first create a connection at the beginning of the session, and then occasionally send a message during the session, so to maintain a permanent and persistent connection.
Currently, without the while loop, the client closes the connection and I don't know how to find a workaround.
Here is the client code:
import java.net.*;
import java.io.*;
public class ControlClientTest {
private Socket socket = null;
// private BufferedReader console = null;
private DataOutputStream streamOut = null;
public static void main(String args[]) throws InterruptedException {
ControlClientTest client = null;
String IP="127.0.0.1";
client = new ControlClientTest(IP, 5555);
}
public ControlClientTest(String serverName, int serverPort) throws InterruptedException {
System.out.println("Establishing connection. Please wait ...");
try {
socket = new Socket(serverName, serverPort);
System.out.println("Connected: " + socket);
start();
} catch (UnknownHostException uhe) {
System.out.println("Host unknown: " + uhe.getMessage());
} catch (IOException ioe) {
System.out.println("Unexpected exception: " + ioe.getMessage());
}
String line = "";
// while (!line.equals(".bye")) {
try {
Thread.sleep(1000);
//TODO get data from input
// line = console.readLine();
line="1";
if(line.equals("1"))
line="1,123";
streamOut.writeUTF(line);
streamOut.flush();
} catch (IOException ioe) {
System.out.println("Sending error: " + ioe.getMessage());
}
// }
}
public void start() throws IOException {
// console = new BufferedReader(new InputStreamReader(System.in));
streamOut = new DataOutputStream(socket.getOutputStream());
}
}
And here is the Server code:
import java.awt.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class ControlServer {
private Socket socket = null;
private ServerSocket server = null;
private DataInputStream streamIn = null;
public static void main(String args[]) {
ControlServer server = null;
server = new ControlServer(5555);
}
public ControlServer(int port) {
try {
System.out
.println("Binding to port " + port + ", please wait ...");
server = new ServerSocket(port);
System.out.println("Server started: " + server);
System.out.println("Waiting for a client ...");
socket = server.accept();
System.out.println("Client accepted: " + socket);
open();
boolean done = false;
while (!done) {
try {
String line = streamIn.readUTF();
// TODO get the data and do something
System.out.println(line);
done = line.equals(".bye");
} catch (IOException ioe) {
done = true;
}
}
close();
} catch (IOException ioe) {
System.out.println(ioe);
}
}
public void open() throws IOException {
streamIn = new DataInputStream(new BufferedInputStream(
socket.getInputStream()));
}
public void close() throws IOException {
if (socket != null)
socket.close();
if (streamIn != null)
streamIn.close();
}
}
I would like to summarize some good practices regarding the stability of TCP/IP connections which I apply on a daily basis.
Good practice 1 : Built-in Keep-Alive
socket.setKeepAlive(true);
It automatically sends a signal after a period of inactivity and checks for a reply. The keep-alive interval is operating system dependent though, and has some shortcomings. But all by all, it could improve the stability of your connection.
Good practice 2 : SoTimeout
Whenver you perform a read (or readUTF in your case), your thread will actually block forever. In my experience this is bad practice for the following reasons: It's difficult to close your application. Just calling socket.close() is dirty.
A clean solution, is a simple read time-out (e.g. 200ms). You can do this with the setSoTimeoutmethod. When the read() method timeouts it will throw a SocketTimeoutException. (which is a subclass of IOException).
socket.setSoTimeout(timeoutInterval);
Here is an example to implement the loop. Please note the shutdown condition. Just set it to true, and your thread will die peacefully.
while (!shutdown)
{
try
{
// some method that calls your read and parses the message.
code = readData();
if (code == null) continue;
}
catch (SocketTimeoutException ste)
{
// A SocketTimeoutExc. is a simple read timeout, just ignore it.
// other IOExceptions will not be stopped here.
}
}
Good practice 3 : Tcp No-Delay
Use the following setting when you are often interfacing small commands that need to be handled quickly.
try
{
socket.setTcpNoDelay(true);
}
catch (SocketException e)
{
}
Good practice 4 : A heartbeat
Actually there are a lot of side scenario's that are not covered yet.
One of them for example are server applications that are designed to only communicate with 1 client at a time. Sometimes they accept connections and even accept messages, but never reply to them.
Another one: sometimes when you lose your connection it actually can take a long time before your OS notices this. Possibly due to the shortcomings described in good practice 3, but also in more complex network situations (e.g. using RS232-To-Ethernet converters, VMware servers, etc) this happens often.
The solution here is to create a thread that sends a message every x seconds and then waits for a reply. (e.g. every 15 seconds). For this you need to create a second thread that just sends a message every 15 seconds. Secondly, you need to expand the code of good practice 2 a little bit.
try
{
code = readData();
if (code == null) continue;
lastRead = System.currentTimeMillis();
// whenever you receive the heart beat reply, just ignore it.
if (MSG_HEARTBEAT.equals(code)) continue;
// todo: handle other messages
}
catch (SocketTimeoutException ste)
{
// in a typical situation the soTimeout is about 200ms
// the heartbeat interval is usually a couple of seconds.
// and the heartbeat timeout interval a couple of seconds more.
if ((heartbeatTimeoutInterval > 0) &&
((System.currentTimeMillis() - lastRead) > heartbeatTimeoutInterval))
{
// no reply to heartbeat received.
// end the loop and perform a reconnect.
break;
}
}
You need to decide if your client or server should send the message. That decision is not so important. But e.g. if your client sends the message, then your client will need an additional thread to send the message. Your server should send a reply when it receives the message. When your client receives the answer, it should just continue (i.e. see code above). And both parties should check: "how long has it been?" in a very similar way.
You could wrap a thread around the connection and have it periodically send a status to keep the line open, say every 30 seconds or whatever. Then, when it actually has data to send it would reset the keep alive to be 30 seconds after the last transmission. The status could be helpful to see if the client is still alive anyway, so at least it can be a useful ping.
Also, you should change your server code, you appear to only handle one connection at the moment. You should loop and when a socket connection comes in spawn a thread to handle the client request and go back to listening. I may be reading to much into what may just be your test code, though.
Make the client socket connection wrapped around a thread. Use a blocking queue to wait for messages. There should only be a single sender queue throughout your application, so use a singleton pattern.
e.g.
QueueSingleton queue = QueueSingleton.getSenderQueue();
Message message = queue.take() // blocks thread
send(message); //send message to server
When you need to send a message to the server, you can use the blocking queue to send the message.
QueueSingleton queue = QueueSingleton.getSenderQueue();
queue.put(message)
The client thread will wake up and process the message.
For maintaining the connection, use a timer task. This is special type of thread that calls a run method repetitively at specified periods. You can use this to post a message, a ping message, every so often.
For processing the received message, you could have another thread, waiting for messages on another blocking queue (receiver queue). The client thread will put the received message on this queue.
I am building a client/server application, for some socket programming exercise.
Below is construction + run method of my server class. The server awaits a respond from the client, which in this case is just a string.
The problem is that it seems to make two connections when the client respond. From my print statements i can see that all the code in the run method is run twice, and then the first line once again.
Why would dateServer.accept(); accept a connection for only one client request?
public Server() throws Exception {
dateServer = new ServerSocket(3001);
System.out.println("Server lytter på port 3000.");
this.start();
}
public void run() {
while (true) {
try {
System.out.println("waiting for client to request");
Socket client = dateServer.accept();
System.out.println("connection established");
Connect c = new Connect(client);
clients.add(c);
this.sleep(5000);
} catch (Exception e) {
}
}
}
--EDIT--
Client code that talks to server (Message is a simple "wrapper" class"):
System.out.println("Write to server:");
String name = scanner.nextLine();
Message message = new Message(name, null);
oos.writeObject(message);
oos.flush();
If all the prints happen twice there must have been two connections. The first line prints again after that because you're in a loop.
NB:
Never ignore exceptions: especially IOExceptions.
The sleep is completely pointless. accept() will block while there are no incoming connections. You are literally wasting time here.
i have a java client-server app in java, both using the same connection class that contains both send/receive messages.
for some reason, some of the messages i send are received in a malformed order:
here's the code
//set up
_in = new BufferedReader(new InputStreamReader(this._socket.getInputStream()));
_out = new BufferedWriter(new OutputStreamWriter(this._socket.getOutputStream()));
this._socket.setSoTimeout(S_TIMEOUT);
public synchronized boolean send(String message){
try {
_out.write(message);
_out.write(Connection.DELIMITER);
_out.flush();
return true;
} catch (IOException e) {
}
return false;
}
public String receive(){
int c;
try {
String message = "";
System.out.println("Getting message:");
c = _in.read();
while(c != -1 && c != Connection.DELIMITER) {
message += (char) c;
c = _in.read();
}
if (c == -1) {
return null;
}
return message;
} catch (IOException e) { }
return null;
}
some messages, for example "new_order" will might return with "ew_ord".
some characters are lost, others are sent separately. this seems odd as its TCP
could this be an encoding related issue?
Delimiter is (char) 0
socket timeout is 20000 (ie 20 senconds). every 10 seconds i send an empty message to make sure socket does not close
EDIT:
although it was solved using the Scanner, i must say that the original code worked fine for many messages/various machines for a very long time (a few weeks), and then suddenly failed to work with one specific message on one specific machine (other messages went through just fine). i've done socket data transfer in java MANY times and i've written many read/write methods to handle the sockets. it's the first time i ran into this.
although in the original code i set the encoding (in the posted code i didn't), i believe that the problem was encoding related. at one point, the message that was received had every second character missing. afterwards i changed it a bit, and the first/second character of the message were received in a separate message. from my understanding, it's either an encoding issue or some firewall/other security program that was running on the message sender machine, that decided to filter outgoing packets.
Try replacing your receive with a Scanner and let it do the work for you.
// in your setup
Scanner sc = new Scanner(_in).useDelimiter(Connection.DELIMETER);
public String receive() {
try {
return sc.next();
} catch(IOException e) {
return "";
}
}
For starters, I would make sure you're printing exceptions in those catch blocks.
Then, you're using the platform default encoding for converting characters to bytes. If these two processes are running on different machines, it's possible they're using different encodings. I would make sure you're specifying an encoding when you set up the Reader and Writer.
You can use UTF encoding for getting Full String of Message.
U can try this code and I am Sure About this code because i used it in My Chat Application.
String data=" ";
socket = new Socket("localhost",999);
while(true)
{
dos = new DataOutputStream(socket.getOutputStream());
dis = new DataInputStream(socket.getInputStream());
data = dis.readUTF();
jta.append(data +"\n");
}
Where jta is JTextArea.
It's for Client Side
Now For Server Side:
try
{
server = new ServerSocket(999);
Socket soc = server.accept();
while(true)
{
String data="";
try
{
dis = new DataInputStream(soc.getInputStream());
dos = new DataOutputStream(soc.getOutputStream());
data = dis.readUTF();
}
catch(Exception e)
{ }
jta.append(data + "\n");
}
}
catch (IOException e)
{
JOptionPane.showMessageDialog(this, e);
System.exit(-1);
}
I have a fairly complex project that boils down to a simple Client / Server communicating through object streams.
Everything works flawlessly for two consecutive connections (I connect once, work, disconnect, then connect again, work, and disconnect). The client connects, does its business, and then closes. The server successfully closes both the object output stream and the socket, with no IO errors.
When I try to connect a third time, the connection appears to go through (the ServerSocket.accept() method goes through and an ObjectOutputStream is successfully created). No data is passed, however. The inputStream.readUnshared() method simply blocks.
I have taken the following memory precautions:
When it comes time to close the sockets, all running threads are stopped, and all objects are nulled out.
After every writeUnshared() method
call, the ObjectOutputBuffer is
flushed and reset.
Has anyone encountered a similar problem, or does anyone have any suggestions? I'm afraid my project is rather large, and so copying code is problematic.
The project boils down to this:
SERVER MAIN
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
new WorkThread(serverSocket.accept()).start();
}
WORK THREAD (SERVER)
public void run() {
ObjectInputBuffer inputBuffer = new ObjectInputBuffer(new BufferedInputStream(socket.getInputStream()));
while (running) {
try {
Object myObject = inputBuffer.readUnshared();
// do work is not specified in this sample
doWork(myObject);
} catch (IOException e) {
running = false;
}
}
try {
inputBuffer.close();
socket.close();
} catch (Exception e) {
System.out.println("Could not close.");
}
}
CLIENT
public Client() {
Object myObject;
Socket mySocket = new Socket(address, port);
try {
ObjectOutputBuffer output = new ObjectOutputBuffer(new BufferedOutputStream(mySocket.getOutputStream()));
output.reset();
output.flush();
} catch (Exception e) {
System.out.println("Could not get an input.");
mySocket.close();
return;
}
// get object data is not specified in this sample. it simply returns a serializable object
myObject = getObjectData();
while (myObject != null) {
try {
output.writeUnshared(myObject);
output.reset();
output.flush();
} catch (Exception e) {
e.printStackTrace();
break;
} // catch
} // while
try {
output.close();
socket.close();
} catch (Exception e) {
System.out.println("Could not close.");
}
}
Thank you to everyone who may be able to help!
(1) What's ObjectInputBuffer and ObjectOutputBuffer? Did you mean ObjectInputStream & ObjectOutputStream?
(2) If so, calling reset() immediately after creating the ObjectOutputStream is just a waste of time and bandwidth.
(3) Why are you printing 'could not get an input' on an exception creating an output stream?
(4) When you get an exception you should always print its message - don't completely substitute it with your own, that's just throwing away useful information.
(5) You are assuming that any IOException when reading means the end of the stream. Only EOFException means that. Any other IOException should be printed or logged. Clearly you are getting some other exception here and ignoring it.
(6) Why do you keep sending the same object?
From ObjectInputStream API for readUnshared():
Reads an "unshared" object from the
ObjectInputStream. This method is
identical to readObject, except that
it prevents subsequent calls to
readObject and readUnshared from
returning additional references to the
deserialized instance obtained via
this call.
Could this be the problem? Use readObject() instead.