JAVA SOCKET realize disconnect after two writes - java

an app in PC using JAVA io.socket which will sends json to a server device ESP8266on TCP on LAN network
when you are connected and when disconnect sequence is executed from java it self everything is ok .
java is client and device is server , when device cuts the connection (here lets use Hercules on localhost) the java program will not being noticed and when i try to write with outputstreamwriter it dose not trig an exception , exception will be executed after at least two writes to socket after the server is being disconnected and the last two writes which was not being received by server will return success! in java. i have read other programmers use a byte send to see if connection is still alive . the same problem is there too . if i send two write each 20 seconds time in between its going to be 60 seconds before java realize server is disconnected and if i send every 1 second is going to be a lot of ATcommand interrupts for nothing .
here is my code:
public boolean Write(String data){
System.out.println("StartSending");
if(TESocket.Connected)
{
Thread write = new Thread(new Runnable() {
#Override
public void run() {
try
{
outputStreamWriter.write(data);
outputStreamWriter.flush();
}
catch (IOException e)
{
TESocket.Connected=false;
System.out.println("Faild");
System.out.println(e.getCause());
}
}
});
write.start();
return true;
}
else
{
System.out.println("Not Connected");
return false;
}
}
The TESocket is class which handles Socket using Runnable and Connected is a static boolean since there is just one socket at a time here is the connect method
public boolean Connect(){
Thread connect = new Thread(new Runnable() {
#Override
public void run() {
try {
socket= new Socket("127.0.0.1",Integer.parseInt(port));
if(socket.isConnected())
{
inputStreamReader = new InputStreamReader(socket.getInputStream());
outputStreamWriter = new OutputStreamWriter(socket.getOutputStream());
TESocket.Connected=true;
System.out.println("Connected");
}
} catch (IOException e) {
System.out.println("Faild to Connect");
e.printStackTrace();
}
}
});
connect.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(TESocket.Connected)
return true;
else
return false;
}
how can i be noticed if server is out of reach with immediately after sending the write? or is there eny event for noticing that ? maybe some king of asynchronous socket? like it was in QT (Signal Slot for Disconnect)

well By reading method and setting a timeout solved this problem , thanks to reading some post
in read if i am still connected and not receiving any data time out will be thrown which bring me back to the first lie of the while loop
if i receive data i will be bigger than zero which reader will read data and flag the rec=true so the disconnect sequence dose not take in place
if i don't receive any data and timeout dose not occurs the rec=false and exception will not be thrown so the program will o to disconnect routine
setting the timeout to 1 millisecond makes it real-time (proportional to my work) in deadline detection
public boolean Read()
{
if (TESocket.Connected)
{
try {
socket.setSoTimeout(1000);
} catch (SocketException e) {
System.out.println("Problem Timeout");
e.printStackTrace();
}
Thread read = new Thread(new Runnable() {
#Override
public void run() {
int i;
boolean rec=false;
while (true)
{
char[] reader = new char[250];
try {
//while(!inputStreamReader.ready());
i=inputStreamReader.read(reader);
if(i>0) {
System.out.println(reader);
rec=true;
}
// Thread.sleep(2500);
if(!rec)
{
System.out.println("Disconnected");
TESocket.Connected=false;
inputStreamReader.close();
outputStreamWriter.close();
socket.close();
break;
}
rec=false;
}
catch (IOException e)
{
System.out.println("Connected");
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
read.start();
}
return true;
}

Related

Best way to handle many clients (with threads?)

So my question goes here. Now if my Server has over 20 clients, it also has 20 threads and my desktop with an ryzen CPU goes to 100% at usage at 30 Threads. Now I'd like to handle a mass-amount of clients by one server, but the CPU is just getting over-used. My wise is very simple how I do it, but there must be a better way; because I saw many good java servers so far yet. I don't know what I do wrong though. In the following I share my code, how I do it in principle.
while(this.isRunning()) {
ServerSocket server = new ServerSocket(8081);
Socket s = server.accept();
new Thread(new WorkerRunnable(s)).start();
//now here if e.g. over 25 users connect there are 25 threads. CPU is at 100%. Is there a better way to handle this?
The worker runnable is identifing the clients. After that they will get into a chat-room. Its like a group chat for e.g.
Edit: Relevant parts of my very unfinished code which is still very WIP
private boolean state;
private ServerSocket socket;
#Override
public void run() {
while(this.isRunning()==true) {
try {
if(this.socket==null) this.socket = new ServerSocket(this.getPort());
Socket connection = this.socket.accept();
IntroductionSession session = new IntroductionSession(this, connection);
new Thread(session).start();
//register timeout task for 3 secs and handle it async
System.out.println(ManagementFactory.getThreadMXBean().getThreadCount());
//this.handleIncomingConnection(connection);
} catch(Exception e) {
e.printStackTrace();
//System.exit(1);
}
}
}
private class IntroductionSession implements Runnable {
private boolean alive = true;
private BaseServer server;
private Socket socket;
private boolean introduced = false;
public IntroductionSession(BaseServer server, Socket socket) {
this.server = server;
this.socket = socket;
}
private void interrupt() {
System.out.println("Not mroe alive");
this.alive = false;
}
private void killConnection() {
this.killConnection("no_reason");
}
private void killConnection(String reason) {
try {
if(this.from_client!=null) this.from_client.close();
if(this.to_client!=null) this.to_client.close();
this.socket.close();
switch(reason) {
case "didnt_introduce":
System.out.println("Kicked connection, cause it didn't introduce itself");
break;
case "unknown_type":
System.out.println("Kicked unknown connection-type.");
break;
case "no_reason":
default:
//ignore
break;
}
} catch (IOException e) {
switch(reason) {
case "didnt_introduce":
System.out.println("Error at kicking connection, which didn't introduce itself");
break;
case "unknown_type":
System.out.println("Error at kicking unknown connection-type.");
break;
case "no_reason":
default:
System.out.println("Error occured at kicking connection");
break;
}
e.printStackTrace();
}
}
private ObjectInputStream from_client;
private ObjectOutputStream to_client;
#Override
public void run() {
while(this.alive==true) {
try {
if(this.to_client==null) {
this.to_client = new ObjectOutputStream(this.socket.getOutputStream());
//this.to_client.flush();
}
if(this.from_client==null) this.from_client = new ObjectInputStream(this.socket.getInputStream());
//Time runs now, if socket is inactive its getting kicked
new Timer().schedule(new java.util.TimerTask() {
#Override
public void run() {
if(IntroductionSession.this.introduced==false) {
IntroductionSession.this.killConnection("didnt_introduce");
Thread.currentThread().interrupt();
IntroductionSession.this.interrupt();
}
}
}, 5000
);
Object obj = this.from_client.readObject();
while(obj!=null) {
if(obj instanceof IntroductionPacket) {
IntroductionPacket pk = (IntroductionPacket) obj;
introduced = true;
if(isCompatible(pk)==false) {
try {
this.to_client.writeObject(new DifferentVersionKickPacket(BaseServer.version));
this.to_client.close();
this.from_client.close();
IntroductionSession.this.socket.close();
System.out.println("Kicked socket, which uses another version.");
} catch(Exception e) {
Thread.currentThread().interrupt();
//ignore
System.out.println("Error at kicking incompatible socket.");
e.printStackTrace();
}
} else {
this.server.handleIncomingConnection(this.socket, this.from_client, this.to_client);
}
Thread.currentThread().interrupt();
}
}
} catch(StreamCorruptedException e) {
//unknown client-type = kick
this.killConnection("unknown_type");
} catch (IOException|ClassNotFoundException e) {
e.printStackTrace();
this.killConnection("no_reason");
}/* catch(SocketException e) {
}*/
}
Thread.currentThread().interrupt();
}
}
Extending class, which is an actual server:
#Override
public void handleIncomingConnection(Socket connection, ObjectInputStream from_client, ObjectOutputStream to_client) {
new AuthenticationSession(connection, from_client, to_client).run();
}
private class AuthenticationSession implements Runnable {
private Socket socket;
private ObjectInputStream from_client;
private ObjectOutputStream to_client;
public AuthenticationSession(Socket socket, ObjectInputStream from_client, ObjectOutputStream to_client) {
this.socket = socket;
this.to_client = to_client;
this.from_client = from_client;
}
//TODO: Implement app id for access tokens
#Override
public void run() {
try {
while(this.socket.isConnected()==true) {
/*ObjectOutputStream to_client = new ObjectOutputStream(socket.getOutputStream()); //maybe cause problems, do it later if it does
ObjectInputStream from_client = new ObjectInputStream(socket.getInputStream());*/
Object object = from_client.readObject();
while(object!=null) {
if(object instanceof RegisterPacket) {
RegisterPacket regPacket = (RegisterPacket) object;
System.out.println("Username:" + regPacket + ", password: " + regPacket.password + ", APP-ID: " + regPacket.appId);
} else {
System.out.println("IP " + this.socket.getInetAddress().getHostAddress() + ":" + this.socket.getPort() + " tried to send an unknown packet.");
this.socket.close();
}
}
}
}/* catch(EOFException eofe) {
//unexpected disconnect
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
catch(Exception e) {
e.printStackTrace();
System.exit(1);
}
/*catch(Exception e) {
//e.printStackTrace();
Thread.currentThread().interrupt();
}*/
}
}
Please dont look at its very bad formatting and stuff I did in hope to fix it, the tasks dont die whyever though.
Generally, in production grade server code, we don't work with direct creation of socket and handling of requests. It's a nightmare to work with low level sockets, close connections and prevent leaks. Rather, we rely on production grade frameworks such as Java Spring Framework or Play Framework.
My question is, why aren't you using any server-side frameworks such as the ones I listed above?
If you're wondering how these frameworks handle thousands of concurrent requests, look into design patterns such as Thread Pool. These frameworks abstract away the complexities and handle the thread pool for you.
If the clients aren't expected to receive an immediate response, you could also look into introducing messaging queue such as Kafka. The server will pick the messages one by one from the queue and process them. However, bear in mind that this is asynchronous and may not meet your requirements.
If you're not just restricted to one server, you could look into deploying your server code to Azure or AWS VMSS (Virtual machine scale set). Based on CPU load rules you configure, the system will autoscale and dynamically manage resources for you.
I would suggest reading upon system design principles related to servers to reinforce your understanding.
Don't reinvent the wheel.
Since you are doing a Chat Application you need to think of doing a Single Threaded Event Loop.
You can Keep a Map of String (Client id) and Socket (Client socket).
Map<String, Socket> clientSockets;
You Server thread will accept new Client Sockets and will just put it in the above map. Then there will be another Thread which will do the Event Loop and whenever there is data in any of the Client Socket in InputStream it should send that data to all other Client Sockets (Group Chat). This should happen infinitely with a Sleep interval.

readObject() throws EOFException although no data is written yet

I'm currently writing a client-server application where data should be transferred to the server to process the data. For building the connection I use ServerSocket and Socket and for sending the data I use OutputStream + ObjectOutputStream on the client-side and InputStream + ObjectInputStream on the server-side. The connection is currently running on localhost.
The object I try to transfer is a serializable class that only contains String parameters.
The problem I'm facing now is that readObject() immediately throws an EOFException as soon as the OutputStreams of the client are initialized (which leads to an initialization of the InputStreams of the server at the same time) instead of waiting for input from the client.
I send the data from the client using this code:
public void send(DataSet dataSet) {
if (!clientStreamsEstablished) {
initiateClientStreams();
}
try {
out.writeObject(dataSet);
} catch (IOException e) {
e.printStackTrace();
}
}
This method is only called when I hit the "submit"-button in the UI so it will not be executed on start of the application.
The data is currently (already tried a ton of other approaches with and without while() loop etc., etc.) read on the server using this method:
private void waitForInput(ObjectInputStream in, InputStream listeningPort) {
boolean dataReceived = false;
DataSet dataSet = null;
System.out.println("waiting ...");
while (!dataReceived) {
try {
Object temp = in.readObject(); // <-- EOFException is thrown here
boolean test = false;
if (temp instanceof DataSet) {
dataSet = (DataSet) temp;
}
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
break;
}
}
System.out.println("Test 2: " + dataSet.toString());
if (dataReceived) {
waitForInput(in, listeningPort);
}
}
As soon as the client thread on the server reaches this line (see code-comment above) I get this stacktrace:
java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2626)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1321)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
at com.labdashboardserver.ClientThread.waitForInput(ClientThread.java:53)
at com.labdashboardserver.ClientThread.run(ClientThread.java:43)
Exception in thread "Thread-2" java.lang.NullPointerException
at com.labdashboardserver.ClientThread.waitForInput(ClientThread.java:65)
at com.labdashboardserver.ClientThread.run(ClientThread.java:43)
The reason for the second part of the stacktrace containing the NullPointerException is apparent as due to the EOFExcpetion the dataSet never is initialized.
However from my point of view readObject() should block and wait for the client to send ANY data before starting to read it and throw an EOF. I feel like I read through half of Stack Overflow and other forums searching for an answer but the articles I found only discuss reading files or only immediate temporary streams which are closed afterwards.
Edit
I initialize the connection before calling the UI in my main method:
public static void main(String[] args) {
connector = new LabConnector();
connector.run();
if (connector.getConnectionEstablished()) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
frame = new LabUI();
frame.setVisible(true);
} catch (Exception e) {
JOptionPane.showMessageDialog(null,
"Error Message:\n" + e.getMessage() + "\nProgram shutting down!", "Critical Error", 0);
}
}
});
}
While in the LabConnector class I initialize the streams and connection like this:
public void run() {
try {
establishConnection();
} catch (UnknownHostException e) {
retryConnection(e);
} catch (IOException e) {
retryConnection(e);
}
if (connectionEstablished) {
initiateClientStreams();
}
}
private void establishConnection() throws UnknownHostException, IOException {
client = new Socket(HOST_IP_ADRESS, HOST_PORT);
JOptionPane.showMessageDialog(null, "Connected to Server!");
connectionEstablished = true;
}
private void initiateClientStreams() {
try {
sendingPort = client.getOutputStream();
out = new ObjectOutputStream(sendingPort);
clientStreamsEstablished = true;
} catch (IOException e) {
e.printStackTrace();
}
}

Manage all incoming chat messages in java socket programming

I am developing a program that has a chat feature and I am using sockets in it.
In my case, I want to handle each of the client in a different window chat(PLEASE SEE ATTACHED IMAGE).
As of now, when 1 client is connected, there is no problem. But when 2 clients are connected, the first client will be overridden by the 2nd one and he can't receive messages from server not unless I close the connection for the latest client connected(Server still receiving messages from all client although only 1 client can receive from server).
How am I gonna do this? I am using captain casa framework
I want to manage it like what did the image below do.
IMAGE HERE
Here is my code:
Server:
public void mainserver(){
Thread server = new Thread(new Runnable() {
#Override
public void run() {
try {
serverSocket = new ServerSocket(port);
System.out.println("Server Online... \nWaiting for Connections");
} catch (IOException e) {
e.printStackTrace();
}
while (accept){
try {
socket = serverSocket.accept();
System.out.println("New Connection Estasblished!!!");
chatHandler chat = new chatHandler(socket);
chat.start();
} catch (IOException e) {
System.out.println("server not terminate all connections");
System.exit(-1);
}
}
}
});
server.start();
}
public class chatHandler extends Thread{
Socket socket;
public chatHandler(Socket socket){
this.socket = socket;
}
public void run(){
try {
din = new DataInputStream(socket.getInputStream());
dout = new DataOutputStream(socket.getOutputStream());
dout.writeUTF("Hi! Thank you for reaching us! How may I help you!?");
while (!read.equals(".end")){
read = din.readUTF();
if (getServerArea()!=null){
setServerArea(getServerArea()+"\n"+read);
}else {
setServerArea(read);
}
}
System.out.println("end of chat server");
} catch (IOException e) {
e.printStackTrace();
}finally {
System.out.println("Exit");
try {
dout.close();
din.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void serverSend(javax.faces.event.ActionEvent event) { // "Send" button
write = getServerField();
try {
dout.writeUTF(write);
dout.flush();
if (getServerArea()!=null){
setServerArea(getServerArea()+"\n"+write);
setServerField("");
}else {
setServerArea(write);
setServerField("");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(write);
}
Client:
public void client(){
Thread client = new Thread(new Runnable() {
#Override
public void run() {
try {
socket = new Socket("localhost",port);
din = new DataInputStream(socket.getInputStream());
dout = new DataOutputStream(socket.getOutputStream());
while (!read.equals("bye")){
read = din.readUTF();
if (getClientArea()!=null){
setClientArea(getClientArea()+"\n"+read);
}else {
setClientArea(read);
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
din.close();
dout.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
client.start();
}
public void clientSend(javax.faces.event.ActionEvent event) {
write = getClientField();
try {
dout.writeUTF(write);
dout.flush();
if (getClientArea()!=null){
setClientArea(getClientArea()+"\n"+write);
setClientField("");
}else {
setClientArea(write);
setClientField("");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(write);
}
I believe I understand the problem, and how to correct it.
You are using a unique thread (chatHandler) for each new connection.
This thread writes an automatic "Hello" upon connection, but thereafter is dedicated to reading messages (in the while loop you only read din) and updating the console accordingly. Since each thread is managing a reference to din, all incoming messages are OK.
However, it seems that writing back to a client (serverSend) is not in a thread; it is triggered by a button event. At this point, dout will be a reference to the most recent connection, and not a reference to the client intended to get the message. That is why the most recent client gets all future messages.
The correction is to choose the correct 'dout' for the intended client. When the server 'operator' chooses to write a message back (clicking the send button), somehow you need to obtain the correct 'dout' for that client.
One way to do this is to establish dout prior to creating the thread (using socket), and maintain a relationship between each client, and it's corresponding dout (i.e. in a Map).
If the problem is still not clear (that each client must have a unique reference to dout), please let me know and I will try to clarify.

Android AsyncTask stuck

Context:
The following AsyncTask for an android application sends and receives so called Request objects from a server.
If the user makes changes to his stuff in the app, new request objects get generated and added to the synchronization queue. If he then hits the sync-button the AsyncTask is created and executed with his requests as parameters.
The handler finally takes all answers and sets the neccessary consequences in the database. He then finally updates the UI by calling one single method on the UI thread (onPostExecute).
public class RequestSender extends AsyncTask<Request, Void, Boolean>{
// Server data
private String host;
private int port = 1337;
private Socket socket;
private AnswerHandler handler;
public RequestSender(AnswerHandler handler) {
this.host = "hostNameHere";
this.handler = handler;
}
/**
* This method gets started as asynchronous task when you call .run()
* #return
*/
#Override
protected Boolean doInBackground(Request... requests) {
return sendAndReceive(requests);
}
private boolean sendAndReceive(Request... requests) {
boolean isConnected = this.initSocket();
if(isConnected) {
this.send(requests);
this.waitForAnswer();
} else {
handler.setRequests(requests);
}
return isConnected;
}
/**
* Tries to open a socket on the android device to a specified Host
*/
private boolean initSocket() {
try {
SocketAddress sockaddr = new InetSocketAddress(host, port);
socket = new Socket();
socket.connect(sockaddr, 5000);
return true;
} catch (UnknownHostException e) {
System.err.println("Unknown Host in initSocket()");
} catch (IOException e) {
System.err.println("Connection timed out");
}
return false;
}
/**
* Tries to send a request to the server
* #param request
*/
public void send(Request... request) {
if(socket != null) {
try {
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(request);
out.flush();
} catch (IOException e) {
System.err.println("Couldn't write to socket in RequestSender");
}
}
}
/**
* Waits for the answer from the server and reports the result in the handler
*/
private void waitForAnswer() {
try {
socket.setSoTimeout(5000);
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Request[] answers = (Request[]) in.readObject();
socket.close();
handler.setRequests(answers);
} catch (StreamCorruptedException e) {
System.err.println("Failed to open stream from server");
} catch (IOException e) {
System.err.println("Failed to read answers from server");
} catch (ClassNotFoundException e) {
System.err.println("Failed to read class from server");
}
}
#Override
protected void onPostExecute(Boolean a) {
handler.updateUI();
}
}
Now my Problem:
The whole thing works without any problem for a few times (It depends on the goodwill of my phone how many times), but then it seems like the task gets stuck somewhere without giving me any error message on System.err.
Restarting the app solves the problem and it works again without any problem.
I already read that AsyncTasks get executed on one single thread since Honeycomb. I set a timeout on open socket and read in, so a stuck task should terminate after this timeout.
Is there any problem with my code and could you imagine a solution for this?
Recently I face this problem and after debugging a lot and brain storming for a week I finally got the bug.
Ok lets do some homework.
Process to send/receive data
Establish a connection. Let assume connectToServer() is a function that physically connects the device to the server.
The socket/TCP part. In your case you have doInbackground(), in which you are calling initSocket() to initiate a socket connetion.
In real world scenario when you request a connection to a server it takes some time, may be a one or two seconds. So you should wait for that time before initiating a socket connection request. If a socket request send before a connection then it goes to lock state and releases after the default time out is finished which make it stuck.
Programming scenario
connectToServer();
// wait for 1 or 2 second.
initSocket();
Sample code
/* Function to check whether we are physically connected to the server or not */
private boolean isConnEstablished(){
WifiInfo connInfo = mManager.getConnectionInfo();
return mManager.isWifiEnabled() && connInfo.getNetworkId() != -1 && connInfo.getIpAddress() != 0;
}
private void initSocket() {
boolean scanning = true;
int tryCount = 5; // we trying for 5 times
try {
while (scanning && tryCount > 0) {
try {
if (isConnEstablished()) {
try{
Thread.sleep(500);
}catch (InterruptedException e){
Log.e("Yo", "sleep-error");
}
tConnection = new Socket(host, port);
scanning = false;
Log.e(getClass().getName(), "Socket connection established");
}else {
throw new ConnectException();
}
} catch (ConnectException e) {
Log.e(getClass().getName(), "connecting again...");
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Log.e(getClass().getName(), "System sleep-error: " + ex.getMessage());
}
}
tryCount--;
}
}

Java Server socket stuck on accept call (Android Client, Java Server)

Below I have put a fragment of code to help understand my problem. I have a server code, works fine for the first time the client loads and sends a packet. After the first packet is received, the server is stuck on "accept".
I have wireshark configured for this port, and the server is getting those packets. I just wonder why accept wont return more than once. Its driving me nuts.
Server Code
public class DAPool implements Runnable {
private ServerSocket serverSocket;
private ArrayList<DA> pool;
private LinkedList<Socket> clientConnQ;
public DAPool(int newPoolSize, int serverPort) {
try {
serverSocket = new ServerSocket(serverPort, 500, InetAddress.getByName("127.0.0.1"));
} catch (IOException e) {
e.printStackTrace();
return;
}
poolSize = newPoolSize;
clientConnQ = new LinkedList<Socket>();
pool = new ArrayList<DA>(poolSize);
DA deviceThread;
for (int threads = 0; threads < poolSize; threads++) {
deviceThread = new DA();
connPool.add(deviceThread);
deviceThread.start();
}
}
public void run() {
while (true) {
Socket incomingSocket;
try {
incomingSocket = serverSocket.accept();
} catch (IOException e) {
e.printStackTrace();
return;
}
insertNewConnToQ(incomingSocket);
}
}
private class DA extends Thread {
private Socket clientSocket;
private ObjectInputStream inputObjectStream;
public DA() {
}
public void run() {
while (true) {
while (clientConnQ.isEmpty()) {
synchronized (clientConnQ) {
try {
clientConnQ.wait();
} catch (InterruptedException ignored) {
ignored.printStackTrace();
}
}
}
synchronized (clientConnQ) {
clientSocket = (Socket) clientConnQ.removeFirst();
try {
inputObjectStream = new ObjectInputStream(clientSocket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
return;
}
// Do something useful here
}
}
}
}
}
Client Code
public class SendQueue extends Thread {
LinkedList<Message> requestQ;
Message sendRequest, requestMessage;
Socket clientSocket;
OutputStream outputStream;
ObjectOutputStream objectOutputStream;
public SendQueue(Socket newClientSocket) {
requestQ = new LinkedList<Message>();
clientSocket = newClientSocket;
}
public void run() {
while (true) {
synchronized (requestQ) {
while (requestQ.isEmpty()) {
try {
requestQ.wait();
} catch (InterruptedException ignored) {
ignored.printStackTrace();
}
}
sendRequest = requestQ.removeFirst();
}
try {
outputStream = clientSocket.getOutputStream();
objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(sendRequest);
objectOutputStream.flush();
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
}
}
}
public int sendRequest(Message message) {
synchronized (requestQ) {
requestQ.addLast(message);
requestQ.notify();
}
return 0;
}
}
I don't see a timeout being set on the serverSocket.
ServerSocket.accept() is a blocking operation so it will block until either an error occurs, a timeout occurs, or a connection is accepted.
Try
SererSocket.setSOTimeout(10000)
You also don't seem to be closing your streams when your finished.
Are you sure that it is sticking on the accept call? Did you get a stacktrace that shows it waiting on accept?
Assuming it is getting stuck elsewhere I'm wondering if it isn't because clientConnQ is being held in one of your DA instances. The synchronized block covers the // Do something useful here section.
I wonder if it might work if you changed the code to be
synchronized (clientConnQ) {
clientSocket = (Socket) clientConnQ.removeFirst();
}
try {
...
Once you have your clientSocket from clientConnQ then no other instance can process that socket.
Ok, if I got a $ for everytime I asked a silly question :)
Here goes. A client socket connects and thats when a server receives a accept call. For some silly reason I was waiting on accept for receiving further data from the client. Infact, I should just wait for something on the "stream" and then process the stream. I should not wait on the accept for that connection.
Accept is to be called to "connect" to the socket, not to receive data continuously.
Thanks for your all your help. You forced me to think about thread synchronization, the design, sockets in general and finally arrive that the solution.
Fantastic responses people. Thanks.
Siddharth

Categories