the following code is server code in my app:
private int serverPort;
private Thread serverThread = null;
public void networkListen(int port){
serverPort = port;
if (serverThread == null){
Runnable serverRunnable = new ServerRunnable();
serverThread = new Thread(serverRunnable);
serverThread.start();
} else {
}
}
public class ServerRunnable implements Runnable {
public void run(){
try {
//networkConnected = false;
//netMessage = "Listening for Connection";
//networkMessage = new NetworkMessage(networkConnected, netMessage);
//setChanged();
//notifyObservers(networkMessage);
ServerSocket serverSocket = new ServerSocket(serverPort, backlog);
commSocket = serverSocket.accept();
serverSocket.close();
serverSocket = null;
//networkConnected = true;
//netMessage = "Connected: " + commSocket.getInetAddress().getHostAddress() + ":" +
//commSocket.getPort();
//networkMessage = new NetworkMessage(networkConnected, netMessage);
//setChanged();
//notifyObservers(networkMessage);
} catch (IOException e){
//networkConnected = false;
//netMessage = "ServerRunnable Network Unavailable";
//System.out.println(e.getMessage());
//networkMessage = new NetworkMessage(networkConnected, netMessage);
//setChanged();
//notifyObservers(networkMessage);
}
}
}
The code sort of works i.e. if im attempting a straight connection both ends communicate and update.
The issue is while im listening for a connection if i want to quit listening then the server thread continues running and causes problems.
i know i should not use .stop() on a thread so i was wondering what the solution would look like with this in mind?
EDIT: commented out unneeded code.
Close the server socket from an external thread. As per the documentation on Serversocket.close() the blocking accept will throw a SocketException and you can shutdown your thread.
After initializing your ServerSocket, use setSoTimeout. Put the accept in a loop, catching the timeouts. Break from the loop and return from run based on whether you want to continue or not.
Related
Please have a look at the noobish code of mine below.
The intention is to create a server where multiple clients can join and send data constantly.
The works up to 3 clients with no errors, once the 4th client joins in during the three other have started to transfer data through the server freezes.
I dont have log or anything as the tablet completely frozen. Need to force close the app.
I guess it is caused one of the while(true) super solution i've got but cannot figure out why is it not happening earlier before the 4th client joins in.
SERVER:
public class TCPServer extends Thread implements Serializable {
Message receivedMessage = new Message();
ServerSocket serverSocket;
Socket socket;
ObjectInputStream ois;
public static ArrayList<Socket> ClientList = new ArrayList<>();
public void run() {
try {
serverSocket = new ServerSocket(6000);
while(true)
{
socket = serverSocket.accept();
ClientList.add(socket);
ois = new ObjectInputStream(socket.getInputStream());
Thread t = new Thread(new TCPComThread(socket,ois));
t.start();
}
}catch (IOException ioe){
try{
socket.close();
}catch(Exception e)
{e.printStackTrace();
ioe.printStackTrace();}
}
}
And the TCPCOMTHREAD:
class TCPComThread implements Runnable{
private Socket client;
private ObjectInputStream oisFromOutside;
TCPComThread(Socket client, ObjectInputStream oisFromOutside)
{
this.client = client;
this.oisFromOutside = oisFromOutside;
}
public void run(){
MessageToServer obj_message_to_server;
LessonToServer obj_lesson_to_server;
try {
Object aux;
while(!client.isClosed()) {
aux = oisFromOutside.readObject();
if (aux instanceof LessonToServer) {
obj_lesson_to_server = (LessonToServer) aux;
//receivedMessage.obtain();
receivedMessage = new Message();
receivedMessage.obj = obj_lesson_to_server;
LessonToServerHandler.sendMessage(receivedMessage);
}
if (aux instanceof MessageToServer) {
obj_message_to_server = (MessageToServer) aux;
//receivedMessage.obtain();
receivedMessage = new Message();
receivedMessage.obj = obj_message_to_server;
MessageToServerHandler.sendMessage(receivedMessage);
}
}
}catch (Exception e)
{
e.printStackTrace();
}
}
}
Can someone point out what could be causing the above issue?
Thanks
EDIT: I believe the above code is fine, after commenting out everything after the readobject it does not freeze. So the problem is probably with the handler.
HANDLER CODE:
private static Handler LessonToServerHandler = new Handler(){
#Override
public void handleMessage(Message msg){
LessonToServer obj = (LessonToServer) msg.obj;
// SAVE THE IMAGE TO INTERNAL STORAGE
Log.e("SCHOOLID",obj.SchoolID);
Log.e("CHILDID",obj.ChildID);
Log.e("LESSONNAME",obj.Lessonname);
Log.e("LESSONNUMBER",obj.Lessonnumber);
Log.e("RESULT",obj.Result);
Log.e("ISJUNK",obj.IsJunk.toString());
Bitmap bitmap = Coding.decodeBase64(obj.byteArray);
Shared.Utils.saveToInternalStorage(bitmap,obj.SchoolID,obj.ChildID,obj.Lessonname,obj.Lessonnumber,obj.Result, ServerApplication.getAppContext(),obj.IsJunk);
}
};
This looks like a case of "UI thread doing too much work" (based on the amount of "file-write" jobs that are being queued to the UI thread via sendMessage()).
So, how to fix it? It may be time to offload some work to a non-UI thread. Luckily, you already have several: Your TCPComThreads. Based on the code presented, you don't need to do the file-writes on the UI thread anyway. You could simply replace the LessonToServerHandler.sendMessage() call with your existing handleMessage() logic. Keeping this work on the TCPComThread has the added benefit that jobs will be completed just as quickly as they are received (they will "self-throttle", since each job must be written to disk before a new one can be received).
I'm working with two java processes that communicates using sockets.
From the server side, I use this to send info :
public void send(Serializable order)
{
try
{
if (this.clientSocket != null && this.clientSocket.isBound() && this.clientSocket.isConnected())
{
String json = "";
json = mapper.writeValueAsString(order);
log.info("sending to client : " + order.getClass());
json = convertToUTF8(json);
this.output.write(json + "\n");
this.output.flush();
log.info("Message sent to client");
}
else
{
log.info("no client connected");
}
}
catch (Exception e)
{
log.fatal("Exception while trying to send message to client : " + e.getMessage(), e);
}
}
output here is :
private BufferedWriter output;
And on the client side, I try to read data like that :
while (this.running)
{
try
{
String msg = in.readLine();
log.debug("MSG VALUE IS : |"+msg+"|\n\n**********\n");
if ("".equalsIgnoreCase(msg) || msg == null)
{
break;
}
in here is a :
private BufferedReader in;
The problem here is after some time, the server process is blocked, ans if I run the netstat command, I can see that the recv-Q and send-Q values are not at 0.
But I can't reproduce myself the situation, so I wonder what is producing this situation, is ther a way to handle that or do I have to change the way to read data ?
Thanks in advance.
Generally if you are using blocking IO operations from server side code, each client needs to have it's own worker thread that is responsible for sending to that client.
The other option is to use NIO (or some framework that uses NIO) to allow your server to multiplex things.
To avoid blocking you should use thead-per-request.
Very brief example :
public class App {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null; // consider it is properly initialized
while (true /* stub health condition */) {
Socket clientSocket = serverSocket.accept(); // the blocking call
final Worker worker = new Worker(clientSocket);
Thread workerThread = new Thread() {
#Override
public void run() {
// handle request here
worker.send(new Serializable(){} /* stub */);
}
};
workerThread.start();
}
}
}
class Worker {
private Socket clientSocket;
Worker (Socket clientSocket) {
this.clientSocket = clientSocket;
}
public void send(Serializable order) {
// logic
}
}
In my main thread I have a while(listening) loop which calls accept() on my ServerSocket object, then starts a new client thread and adds it to a Collection when a new client is accepted.
I also have an Admin thread which I want to use to issue commands, like 'exit', which will cause all the client threads to be shut down, shut itself down, and shut down the main thread, by turning listening to false.
However, the accept() call in the while(listening) loop blocks, and there doesn't seem to be any way to interrupt it, so the while condition cannot be checked again and the program cannot exit!
Is there a better way to do this? Or some way to interrupt the blocking method?
You can call close() from another thread, and the accept() call will throw a SocketException.
Set timeout on accept(), then the call will timeout the blocking after specified time:
http://docs.oracle.com/javase/7/docs/api/java/net/SocketOptions.html#SO_TIMEOUT
Set a timeout on blocking Socket operations:
ServerSocket.accept();
SocketInputStream.read();
DatagramSocket.receive();
The option must be set prior to entering a blocking operation to take effect. If the timeout expires and the operation would continue to block, java.io.InterruptedIOException is raised. The Socket is not closed in this case.
Is calling close() on the ServerSocket an option?
http://java.sun.com/j2se/6/docs/api/java/net/ServerSocket.html#close%28%29
Closes this socket. Any thread currently blocked in accept() will throw a SocketException.
You can just create "void" socket for break serversocket.accept()
Server side
private static final byte END_WAITING = 66;
private static final byte CONNECT_REQUEST = 1;
while (true) {
Socket clientSock = serverSocket.accept();
int code = clientSock.getInputStream().read();
if (code == END_WAITING
/*&& clientSock.getInetAddress().getHostAddress().equals(myIp)*/) {
// End waiting clients code detected
break;
} else if (code == CONNECT_REQUEST) { // other action
// ...
}
}
Method for break server cycle
void acceptClients() {
try {
Socket s = new Socket(myIp, PORT);
s.getOutputStream().write(END_WAITING);
s.getOutputStream().flush();
s.close();
} catch (IOException e) {
}
}
The reason ServerSocket.close() throws an exception
is because you have an outputstream or an inputstream
attached to that socket.
You can avoid this exception safely by first closing the input and output streams.
Then try closing the ServerSocket.
Here is an example:
void closeServer() throws IOException {
try {
if (outputstream != null)
outputstream.close();
if (inputstream != null)
inputstream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
if (!serversock.isClosed())
serversock.close();
}
}
You can call this method to close any socket from anywhere without getting an exception.
Use serverSocket.setSoTimeout(timeoutInMillis).
OK, I got this working in a way that addresses the OP's question more directly.
Keep reading past the short answer for a Thread example of how I use this.
Short answer:
ServerSocket myServer;
Socket clientSocket;
try {
myServer = new ServerSocket(port)
myServer.setSoTimeout(2000);
//YOU MUST DO THIS ANYTIME TO ASSIGN new ServerSocket() to myServer‼!
clientSocket = myServer.accept();
//In this case, after 2 seconds the below interruption will be thrown
}
catch (java.io.InterruptedIOException e) {
/* This is where you handle the timeout. THIS WILL NOT stop
the running of your code unless you issue a break; so you
can do whatever you need to do here to handle whatever you
want to happen when the timeout occurs.
*/
}
Real world example:
In this example, I have a ServerSocket waiting for a connection inside a Thread. When I close the app, I want to shut down the thread (more specifically, the socket) in a clean manner before I let the app close, so I use the .setSoTimeout() on the ServerSocket then I use the interrupt that is thrown after the timeout to check and see if the parent is trying to shut down the thread. If so, then I set close the socket, then set a flag indicating that the thread is done, then I break out of the Threads loop which returns a null.
package MyServer;
import javafx.concurrent.Task;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import javafx.concurrent.Task;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
public class Server {
public Server (int port) {this.port = port;}
private boolean threadDone = false;
private boolean threadInterrupted = false;
private boolean threadRunning = false;
private ServerSocket myServer = null;
private Socket clientSocket = null;
private Thread serverThread = null;;
private int port;
private static final int SO_TIMEOUT = 5000; //5 seconds
public void startServer() {
if (!threadRunning) {
serverThread = new Thread(thisServerTask);
serverThread.setDaemon(true);
serverThread.start();
}
}
public void stopServer() {
if (threadRunning) {
threadInterrupted = true;
while (!threadDone) {
//We are just waiting for the timeout to exception happen
}
if (threadDone) {threadRunning = false;}
}
}
public boolean isRunning() {return threadRunning;}
private Task<Void> thisServerTask = new Task <Void>() {
#Override public Void call() throws InterruptedException {
threadRunning = true;
try {
myServer = new ServerSocket(port);
myServer.setSoTimeout(SO_TIMEOUT);
clientSocket = new Socket();
} catch (IOException e) {
e.printStackTrace();
}
while(true) {
try {
clientSocket = myServer.accept();
}
catch (java.io.InterruptedIOException e) {
if (threadInterrupted) {
try { clientSocket.close(); } //This is the clean exit I'm after.
catch (IOException e1) { e1.printStackTrace(); }
threadDone = true;
break;
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
};
}
Then, in my Controller class ... (I will only show relevant code, massage it into your own code as needed)
public class Controller {
Server server = null;
private static final int port = 10000;
private void stopTheServer() {
server.stopServer();
while (server.isRunning() {
//We just wait for the server service to stop.
}
}
#FXML private void initialize() {
Platform.runLater(()-> {
server = new Server(port);
server.startServer();
Stage stage = (Stage) serverStatusLabel.getScene().getWindow();
stage.setOnCloseRequest(event->stopTheServer());
});
}
}
I hope this helps someone down the road.
Another thing you can try which is cleaner, is to check a flag in the accept loop, and then when your admin thread wants to kill the thread blocking on the accept, set the flag (make it thread safe) and then make a client socket connection to the listening socket.
The accept will stop blocking and return the new socket.
You can work out some simple protocol thing telling the listening thread to exit the thread cleanly.
And then close the socket on the client side.
No exceptions, much cleaner.
You can simply pass the timeout limit (milli seconds) as a parameter while calling accept function.
eg serverSocket.accept(1000);
automatically close the request after 1 sec
i have coded a socket listener that should listen on port 80 and 81 and when data arrive on these ports execute operations on these data. I want this listener to concurrently listen on both these ports and hav coded in the following way.
import java.net.*;
import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
public class MultipleSocketServer implements Runnable {
private int a;
private ServerSocket connection;
private String TimeStamp;
private int ID;
public static void main(String[] args){
// System.out.print("ip");
// String gh="12345";
//System.out.println(gh.substring(1,3));
int port = 80;
int port1 = 81;
int count = 0;
double a=234.52121;
//System.out.println(bf3.toString());
try{
ServerSocket socket1 = new ServerSocket(port);
ServerSocket socket2=new ServerSocket(port1);
System.out.println("MultipleSocketServer Initialized");
Runnable runnable = new MultipleSocketServer(socket1, ++count);
Runnable run = new MultipleSocketServer(socket2, ++count);
Thread thread = new Thread(runnable);
Thread thread1 = new Thread(run);
while (true) {
//Socket connection = socket1.accept();
thread.start();
thread1.start();
}
}
catch (Exception e) {}
}
MultipleSocketServer(ServerSocket s, int i) {
this.connection = s;
this.ID = i;
}
public void run() {
while(true){
try {
Socket incoming=connection.accept();
BufferedInputStream is = new BufferedInputStream(incoming.getInputStream());
int character;
while((character = is.read())!=-1) {
.
.
do the input data handling here
.
.
}
}
catch(Exception e){}
}
}
}
But for some reason this does not seem to show the threaded/conncurrent behaviour.
I am testing this code using Hyperterminal, and every time i disconnect from hyperterminal, the program execution stops and "Socket is closed" exception is raised.
Any pointers would be of great help
Cheers
You're starting threads in an endless loop.
while (true) {
//Socket connection = socket1.accept();
thread.start();
thread1.start();
}
I think though, that this is handled (ignored) in
} catch (Exception e) {}
However, I suspect that the problem you describe is in in the handling code you didn't include. One pretty obvious idea: you don't call connection.close() instead of incoming.close(), do you?
I've written a simple application in Java where there are two nodes, each with a ServerSocket open to a port listening for incoming connections. The nodes run two threads each, sending 1000 messages to the other node through a persistent TCP socket created when sending the first message. However, the nodes do not receive all 1000 messages. One may receive 850 while the other only receives 650. This number tends to stay constant over multiple runs.
The sending code is as follows:
public void SendMsg(String dest, Message myMsg) {
Socket sendsock = null;
PrintWriter printwr = null;
try {
if(printwr == null) {
sendsock = new Socket(dest, Main.rcvport);
printwr = new PrintWriter(sendsock.getOutputStream(), true);
}
String msgtosend = myMsg.msgtype.toString() + "=" + Main.myaddy + "=" + myMsg.content + "\n";
printwr.print(msgtosend);
} catch (UnknownHostException ex) {
System.out.println(ex);
//DO: Terminate or restart
} catch (IOException ex) {
System.out.println(ex);
//DO: Terminate or restart
}
}
Performance seems to improve if I use
buffwr = new BufferedWriter(printwr)
as well and use buffwr.write(...) instead of printwr.print(...), though it doesn't seem to be a complete solution for the data loss. There are no exceptions to show that packets weren't delivered, so according to the sender, they were all sent successfully.
On the receiving end, the accepted connection is treated as follows:
BufferedReader inbuff = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
while(running) {
String rcvedln = inbuff.readLine();
if(rcvedln != null) {
count++;
System.out.println(count);
}
}
Is there an problem with how the readers and writers have been used that could be causing the problem? Thanks.
SendMsg() is creating a new socket every call, so you aren't using a persistent TCP connection. The method isn't closing the socket, either, so you have a lot of open collections. You may be reaching a limit to the number of connections the process can make (the sockets may not be closed when the objects are garbage collected).
Finally, as kd304 pointed out, the Javadoc for PrintWriter states this about the autoFlush parameter of the PrintWriter constructor: "if true, the println, printf, or format methods will flush the output buffer". Your code wasn't calling a method that did a flush.
Try this:
public class MessageSender implements Closeable {
private final Socket socket;
private final PrintWriter writer;
public MessageSender(String dest, int port) {
socket = new Socket(dest, port);
writer = new PrintWriter(socket.getOutputStream(), true);
}
public void sendMessage(Message message) {
try {
writer.println(message.toString());
} catch (UnknownHostException ex) {
System.out.println(ex);
//DO: Terminate or restart
} catch (IOException ex) {
System.out.println(ex);
//DO: Terminate or restart
}
}
#Override
public void close() throws IOException {
writer.close();
socket.close();
}
Note I modified the code so that sendMessage() calls Message.toString() to get the formatted message. It doesn't seem right for sendMessage() to reference fields in Message in order to format the message. Instead of using toString() you could create a method in Message specifically for this purpose.
Here's the server side code:
public class Server implements Runnable {
private final ServerSocket serverSocket;
private final ExecutorService executor;
private volatile boolean running = true;
public Server(int port, ExecutorService executor) throws IOException {
serverSocket = new ServerSocket(port);
this.executor = executor;
}
#Override
public void run() throws IOExeption {
while (running) {
Socket socket = serverSocket.accept();
executor.execute(new ConnectionHandler(socket));
}
}
public boolean stop(long timeout, TimeUnit unit) {
running = false;
executor.shutdown();
return executor.awaitTermination(timeout, unit);
}
}
You can use Executors to create an ExecutorService to run the tasks. Note that ConnectionHandler needs to close the socket it is given.
Are you closing out the PrintWriter to flush the stream?
} finally {
printwr.close();
sendsock.close();
}
Ah, sorry. I accidentally removed the commenting from the code. It's actually like this:
public void SendMsg(String dest, Message myMsg) {
Socket sendsock = null;
try {
if(printwr == null) {
sendsock = new Socket(dest, Main.rcvport);
printwr = new PrintWriter(sendsock.getOutputStream(), true);
}
String msgtosend = myMsg.msgtype.toString() + "=" + Main.myaddy + "=" + myMsg.content + "\n";
printwr.print(msgtosend);
} catch (UnknownHostException ex) {
System.out.println(ex);
//DO: Terminate or restart
} catch (IOException ex) {
System.out.println(ex);
//DO: Terminate or restart
}
}
printrw is declared and stored outside the function, so once it's set up, there is no need for sendsock or for reinitializing printrw. In the actual application, I'm storing the PrintWriter for every connection in a HashMap and retrieving it at the start of the SendMsg(...) function.
Since the connections are persistent, every time one is accepted, a new thread is lunch that runs a while loop to check it continuously for data. These threads and connections are only closed once the application is terminated. In addition to my previous question, is there a more efficient way of doing this?
Earlier, I'd implemented this code without the "\n" and using println(...) instead and I still had the issue of some messages not being received, so I'm not sure what is causing the problem. The messages are sent like so:
public class SendPortal2 implements Runnable {
String dest = null;
SendPortal2 (String dest) {
this.dest = dest;
}
public void run() {
for(int i=1; i<1000; i+=2) {
Message myMsg = new Message("Message", Main.myaddy + " " + String.valueOf(i));
Main.myCommMgr.SendMsg(dest, myMsg);
}
}
}
There are two such threads running. When I ran the code again just now, one side got 999 packets whereas the other one only got 500, leading me to believe sometimes the data from an entire thread could be blocked out. Is that likely?
Thanks for the replies!
If I put a Thread.sleep(2) inside the for loop where the SendMsg function is called, more messages are received properly, but it's not always 1000. Could it be possible that the system's resources are being hogged by two threads running while loops continuously?