I have a multithreaded TCP Server in Java which allows connections from several clients and starts a new ServerThread for each connected Client:
Server Class:
while (!Thread.currentThread().isInterrupted()) {
try {
// Create a new thread for each incoming connection.
Socket clientSocket = serverSocket.accept();
ServerThread serverThread = new ServerThread(clientSocket, this);
serverThread.run();
} catch (IOException e) {
e.printStackTrace();
}
}
After a specific timeout, a client closes its socket. How can I interrupt the ServerThread which was connected with the client?
clientsocket.isClosed() and !clientSocket.isConnected() don't work for some reason.
Finally, I got it working with the following snippets (the solution is the socket in the resource block and the endless in.readLine() == null):
Server class
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
// Create a new thread for each incoming connection.
Socket clientSocket = serverSocket.accept();
ServerThread serverThread = new ServerThread(clientSocket, this);
serverThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ServerThread class:
public void run() {
try (Socket socket = clientSocket; // Enable auto-close for socket...
PrintWriter out = ...; BufferedReader in = ...;) {
...
while (!clientSocket.isClosed() && !isInterrupted()) {
if (in.readLine() == null) {
break;
}
}
System.err.println("Client with port " + clientSocket.getPort() + " closed connection to server.");
} catch (IOException e) {
e.printStackTrace();
}
}
Client class: I use the same try with resource block as in the ServerThread class
If the client closes a TCP socket uncleanly without sending an explicit FIN (for example, if the client crashes) then the server will not know about it until it next tries to send a packet to the client (at which point the client will sent an RST packet to tell the server the socket was closed).
Assuming you have control of both client and server code, the most robust way to check the connection is to implement a heartbeat mechanism between the two so they are regularly pinging a small piece of data between them to check the validity of the connection.
Keep alive socket option is the standard way to watch persistent TCP connection.
If your server was in the blocking read operation during the abort you'll get java.io.IOException: read failed. In the asynchronous case you'll receive read key with -1.
In the write state you'll get: Connection reset by peer: socket write error.
Just handle the exceptions or error codes to shutdown the thread if connection is not recoverable.
Related
I created class SocketListener to receive data through TCP protocol. My start method looks like this:
public void start() throws IOException {
LOGGER.log(Level.INFO, "SOCKET LISTENER STARTED PORT: " + port);
serverSocket = new ServerSocket(port);
while (true) {
FrameParser fp;
try {
socket = serverSocket.accept();
fp = new FrameParser(socket);
Thread thread = new Thread(fp);
thread.start();
} catch (Exception e) {
resetConnection();
}
}
}
Writing this code I based on example from oracle website (http://www.oracle.com/technetwork/java/socket-140484.html#server). When I placed line with serverSocket.accept() inside loop some of the packets was not received by ServerSocket. I am sure that this TCP packets was received on my network interface bacause I checked it later using Wireshark. I have no idea what causes that problem so I tried different things and I noticed that more packets was received when I change my code like this:
public void start() throws IOException {
LOGGER.log(Level.INFO, "SOCKET LISTENER STARTED PORT: " + port);
serverSocket = new ServerSocket(port);
socket = serverSocket.accept();
while (true) {
FrameParser fp;
try {
fp = new FrameParser(socket);
Thread thread = new Thread(fp);
thread.start();
} catch (Exception e) {
resetConnection();
}
}
}
I made this modification using trial and error method and unfortunately after this change my application started receive more data than I filtered in Wireshark (for example in Wireshark I saw 10 packets but my application created hundreds of new threads and it finished with out of memory error).
What can be a reason that in a first case not all of TCP packets reached to socket?
I'm trying to use TCP with an Android app, so there are two projects, one is the server and one is the client.
When I run the server and open the client, everything works fine and messages are being delivered to both sides, although when I close the app (from an emulator), it won't alert me in the console that the socket connection was closed and attempt to get another connection so when trying to re-open the app, it won't reconnect and messages won't be delivered.
So what am I really doing wrong here? I'm new to Android and TCP, so I'm sorry if this is quite a rookie question.
#Override
public void run() {
super.run();
running = true;
try {
System.out.println("S: Connecting...");
//create a server socket. A server socket waits for requests to come in over the network.
ServerSocket serverSocket = new ServerSocket(SERVERPORT);
//create client socket... the method accept() listens for a connection to be made to this socket and accepts it.
while (running) {
Socket client = serverSocket.accept();
try {
//sends the message to the client
mOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true);
//read the message received from client
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
//in this while we wait to receive messages from client (it's an infinite loop)
//this while it's like a listener for messages
while(!client.isClosed()) {
String message = in.readLine();
if (message != null && messageListener != null) {
//call the method messageReceived from ServerBoard class
messageListener.messageReceived(message);
}
}
} catch (Exception e) {
System.out.println("S: Error");
e.printStackTrace();
} finally {
client.close();
System.out.println("S: Done.");
}
}
} catch (Exception e) {
System.out.println("S: Error");
e.printStackTrace();
}
}
It would be more accurate to say that you aren't testing for disconnection correctly.
Socket.isClosed() does not magically become true when the peer disconnects. So using it to control a read loop is futile. It only tells you whether you have closed this socket.
readLine() returns null when the peer has disconnected, but you're treating it as just another value.
A correct loop using readLine() looks like this:
while ((line = in.readLine()) != null)
{
// ...
}
I am working with Java sockets. I have a server socket and two client sockets. My problem is, that the first client socket submits its message to my server socket, and the message from the second client socket is not arriving at the server socket. That means, that for the first client socket the while loop is interrupted after a succesful message, and the second client ends in an infinite while loop. If I test each client socket seperately in a test class, each client socket is submitting its message correctly to my server socket. By watching TCPView I noticed, that the client socket does not respond, as long as my port is used.
I read, that the second client socket should still respond its message, even if the port was used. In my case, the second client socket should always respond about a second after the first one. But I can't get them to work one after another.
So, here is my code for the method, which is waiting for client messages:
public void listenToSocket()
{
serverSocket = null;
thread = null;
SocketAddress adress = new InetSocketAddress(CommunicationValues.SOCKET_PORT);
try {
serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(adress);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
System.exit(0);
}
while(true){
try
{
Socket clientSocket = serverSocket.accept();
thread = new SocketMessageThread(clientSocket);
thread.start();
} catch (IOException e) {
System.out.println("MyServerSocket caught an error: \n" + e.getMessage());
e.printStackTrace();
}
}
}
This method is called in a thread. The structure looks like this:
SocketListenerThread calls the method listenToSocket() from class SocketListener
listenToSocket() is described above
The SocketMessageThread is handling the message output of the client socket in its run()-method.
EDIT
Here is the code of my SocketMessageThread:
public class SocketMessageThread extends Thread{
private Socket clientSocket;
private static int nameCounter = 0;
public SocketMessageThread(Socket clientSocket) {
this.clientSocket = clientSocket;
this.setDaemon(true);
this.setName("SocketMessageThread" + (nameCounter++));
}
public void run() {
try (
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));)
{
while (in.ready())
{
String inLine = in.readLine();
CommunicationValues.MESSAGE_MEMORIZER = inLine;
}
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}}
EDIT 2
Both clients only communicate with one particular message. E.g. when a client is started up, it mentioned, that the startup was successful with a single message. There are no repeating messages coming from the client sockets until the server sockets catches them. So if the server socket doesn't catch that one message, it's gone, and it won't be sent again by the client socket.
while (in.ready())
{
// ...
}
Classic misuse of ready(). Exchange all this for:
String inLine;
while ((inLine = in.readLine()) != null)
{
CommunicationValues.MESSAGE_MEMORIZER = inLine;
}
Presumably there is more code that you haven't shown us: otherwise all this will do is memorize the last line sent.
I'm learning about java sockets in a class of mine. I'm having issues with the communication between the peers. My question is why am I receiving this exception:
Exception java.net.ConnectionException: Connection refused: connect
for example:
in my main thread
ServerSocket listenSock = new ServerSocket(Integer.parseInt(argv[2]),0,InetAddress,getByName(null));
//Create Server loop to process inbound connections
while(true){
//accept an incoming client by saving it to a socket to use to communicate with it
Socket clientSock = listenSock.accept();
/waa/create a thread to handle the inbound client so that we can return to accept()
InboundHandler inboundMsg = new InboundHandler(clientSock); // listens to the peers outbound socket
Thread inThread = new Thread(inboundMsg);
inThread.start();
// add the peer to the list.
}
in a seperate thread I have a
public InboundHandler(Socket socket) throws Exception{
this.socket = socket; //save the socket object to "this" instance of the class
input = new BufferedReader(new InputStreamReader(socket.getInputStream())); // listens from the clients speaking socket
}
public void run(){
while(true){
try{
String line = input.readLine();
System.out.println(line);
}catch(IOException e){
System.out.println("Could not read input. " + e);
}
}
and finally I have a thread that sends out messages
for(int i=0;i<portList.size(); i++){
if(nameList.get(i)!=Username){
Socket peerSocket= new Socket(InetAddress.getByName(null),portList.get(i));
writer = new BufferedWriter(new OutputStreamWriter(peerSocket.getOutputStream()));
writer.write(Username + " has connected");
writer.flush();
}
}
}
catch(IOException e){
System.out.println("Some IO problem. " + e);
}
My program compiles, and when I run it, I receive the Exception
java.net.ConnectionException: Connection refused: connect
From what it's sounding like, is the port that my one peer is trying to speak to, isn't being heard by the other peers. But this is more guessing
As for the while(true) I am going to change that later, with a boolean statement.
I have a server in Java which listens for incoming connection to a specific port. And everything works as expected, my clients connect to the server and I'm able to send data between them.
My problem is that, when I shut down my client, turn it on again and try to reconnect, it won't connect (my server stays on all the time).
For me to reconnect, I have to restart my server again.
So I tried doing this on my server side:
InetSocketAddress serverAddr = new InetSocketAddress(serverIpAddress, serverPort);
serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
//I tries setting up a reuse option
serverSocket.bind(serverAddr);
Even after setReuseAddress() my client won't connect unless I restart my server!
Has anyone any idea of how could that be done?
EDIT2:
try {
while(true){
clientSocket = serverSocket.accept();
System.out.println("S-a conectat clientul de monitorizare!");
os=new ObjectOutputStream(clientSocket.getOutputStream());
try{
coord=(Coordinate)queue.take();
System.out.println(coord.getLat()+coord.getLon()+coord.getVit()+coord.getwId()+coord.getime());
os.writeObject(coord);
os.flush();
}
catch(Exception e)
{
e.printStackTrace();
}
}
} catch (IOException e) {
System.out.println(e);
try {
clientSocket.close();
os.close();
}catch(Exception e1) {
e1.printStackTrace();
}
}
New edit:
Thread pool server:
Main:
ThreadPooledServer server = new ThreadPooledServer(queue,7001);
new Thread(server).start();
ThreadPooledServer:
public class ThreadPooledServer implements Runnable {
protected ExecutorService threadPool =
Executors.newFixedThreadPool(5);
public void run() {
openServerSocket();
while (!isStopped()) {
Socket clientSocket = null;
try {
System.out.println("Serverul asteapta clienti spre conectare");
clientSocket = this.serverSocket.accept();
clientconnection++;
System.out.println("Serverul a acceptat clientul cu numarul:"
+ clientconnection);
} catch (IOException e) {
if (isStopped()) {
System.out.println("Server Stopped.");
return;
}
throw new RuntimeException("Error accepting client connection",
e);
}
WorkerRunnable workerRunnable = new WorkerRunnable(queue,clientSocket);
this.threadPool.execute(workerRunnable);
}
System.out.println("Server Stopped.");
}
public synchronized void stop() {
this.isStopped = true;
try {
this.threadPool.shutdown();
}
catch (IOException e) {
throw new RuntimeException("Error closing server", e);
}
}
private void openServerSocket() {
try {
InetSocketAddress serverAddr = new InetSocketAddress(SERVERIP,
serverPort);
serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(serverAddr);
} catch (IOException e) {
throw new RuntimeException("Cannot open port", e);
}
}
this.serverSocket.close();
In your run method you accept one client and then go in to an endless loop, trying to write data to the ObjectOutputStream. When the client closes the connection an exception is thrown because you can no longer write to the stream. At this point we're out of the endless loop(while(true) { .. }) and the run method ends.
If you want to keep accepting clients I suggest you move the while loop to the top of your code, above the accept to be exact.
Pseudo-ish code below(note: I'm not catching any exceptions etc.):
while (true)
{
// Wait for a client to connect..
Socket clientSocket = serverSocket.accept();
// Write to the client..
ObjectOutputStream os = new ObjectOutputStream(clientSocket.getOutputStream());
os.writeObject(coord);
os.flush();
}
Is your server single threaded for a purpose (do you only accept one client at a time) ? Usually, servers will spawn a separate thread for every connections, so it can listen more often for incoming connections, and so if the client's connection throws any errors, it won't affect the listening socket. At the moment, your server will listen to only one connection, and if an exception occurs handling the client's connection, simply move on and never listen again. In pseudocode, a typical server is like :
Server listening thread (main thread)
try {
create server socket and bind to port
while server is online
listen for incoming connections
if the client connection is accepted [1]
start client thread
catch exception
handle exception
finally
make sure the server socket is disconnected
cleanup
Server client connection thread
write to client socket to initialize connection
try
while scoket is opened
read data
data treatment
write response
catch exceptions
handle exception [2]
finally
close client socket
cleanup
[1] if your server handles only one client, it should refuse the connection, so the client doesn't wait for no reason
[2] if the exception is not about the socket, the client should be warned by a final write to the socket before closing it
Client thread (on the client's side)
try
connect to server
protocol handshake (optional) [4]
while socket is connected
client server communication
catch exception
handle excpetion
finally
close socket
[4] since the server should write to the socket first, the client should read from it for any welcome message or error messages before attempting to write anything.