Synchronization of Sockets & Threads

I have this socket server that accepts connections from clients and it then calls a new thread to deal with each client request. I pass the client socket and a data source into the new thread so that the thread will be able to open an input/output stream to the client. The thread reads in the input from the client and currently just sends it right back. The part that gets tricky for me is when I clean up everything by closing the client socket connection after the thread has finished. Everything works fine for simple requests, but sometimes a client will need to send 4 or 5 requests all at the same time which ends up giving me a SocketException: Socket Closed.

The error is always on the following line: inStream.read( size, 0, RECORD_LENGTH_BYTES );

I assume that the threads are closing sockets over each other which causes the problem. I've tried putting in synchronized methods and synchronized statements but it doesn't seem to help.

Any advice on this would be greatly appreciated.

Here is the Thread code:

import java.net.*;

import java.io.*;

import java.sql.Connection;

import java.sql.SQLException;

import javax.sql.DataSource;

/*

*

*/

publicclass SocketServerThreadextends Thread{

privatestatic Socket socket =null;

privatestatic Connection conn=null;

privatestatic OutputStream outStream =null;

privatestatic DataSource ds =null;

privatestaticfinalint RECORD_LENGTH_BYTES = 4;

privatestatic InputStream inStream =null;

privatestaticint counter = 0;

public SocketServerThread(Socket theSocket, DataSource theDs){

super("SocketServerThread");

socket = theSocket;

ds = theDs;

}

publicvoid run(){

String response ="";

int index = 0;

StringBuffer buffer =new StringBuffer();

System.out.println("New Client Requesting...");

//Set up data source connection

//dataSourceConnection();

try{

inStream = socket.getInputStream();

outStream = socket.getOutputStream();

}catch (UnknownHostException e){

System.err.println("Don't know about host.");

clean();

}catch (IOException e){

System.err.println("Couldn't get I/O for "

+"the connection.");

clean();

}

try

{

// read acknowledgement

// read the first 4 bytes - see how long the response message is

byte[] size =newbyte[RECORD_LENGTH_BYTES];

inStream.read( size, 0, RECORD_LENGTH_BYTES );

for (index = 0; index < RECORD_LENGTH_BYTES; index++)

{

buffer.append((char)size[index]);

}

// The number of bytes left in the inputstream to read in

try

{

int recordLength = (new Integer(buffer.toString()).intValue())

- RECORD_LENGTH_BYTES;

byte[] msg =newbyte[recordLength];

inStream.read( msg, 0, recordLength );

for (index = 0; index < recordLength; index++)

{

buffer.append((char)msg[index]);

}

}

catch (NumberFormatException nfe)

{

System.out.println("Unless running Connection Pool "

+"/ Factory J-Units, you should NOT see this message");

clean();

}

System.out.println("- " + ++counter

+" -");

System.out.println("*** EbtTestServer Recieved: "

+ buffer.toString());

response = buffer.toString();

outStream.write( response.getBytes() );

outStream.flush();

}catch(IOException e){e.printStackTrace(); clean();}

clean();

}

privatesynchronizedstaticvoid clean()

{

try{

socket.close();

inStream.close();

outStream.close();

//conn.close();

}catch(IOException e){e.printStackTrace();}

//catch(SQLException s){s.printStackTrace();}

}

}

Here is the socket server code:

import java.net.*;

import java.io.*;

import javax.naming.*;

import javax.sql.DataSource;

import java.sql.Connection;

import java.util.Hashtable;

/*

*

*/

publicclass SocketServer{

staticboolean listening =true;

publicfinalstatic String JNDI_FACTORY="weblogic.jndi.WLInitialContextFactory";

privatestatic ServerSocket serverSocket =null;

privatestatic DataSource ds =null;

publicvoid endListening()

{

listening =false;

}

privatestaticvoid usage()

{

System.err.println("Usage: SocketServer " +"<hostname> <port number>");

System.exit(-1);

}

publicstaticvoid main(String[] argv)throws IOException

{

// Get hostname and port from arguments

if (argv.length < 2)

{

usage();

}

String host = argv[0];

int port = 0;

InitialContext ic =null;

//Connection conn = null;

try

{

port = Integer.parseInt(argv[1]);

}

catch (NumberFormatException nfe)

{

usage();

clean();

}

// Set up Socket Server on Port

try{

serverSocket =new ServerSocket(4444);

}catch (IOException e){

System.err.println("Could not listen on port: 4444.");

clean();

System.exit(-1);

}

//Set up connection to DB

try

{

ic = getInitialContext("t3://" + host +":" + port);

ds = (DataSource) ic.lookup("data-source");

}

catch (Throwable t)

{

t.printStackTrace();

clean();

System.exit(-1);

}

System.out.println("Server Running...");

// Wait for connection from client, then create new thread to handle client

while(listening)

{

new SocketServerThread(serverSocket.accept(), ds).start();

}

clean();

}

privatestatic InitialContext getInitialContext(String url)

throws NamingException

{

Hashtable env =new Hashtable();

env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);

env.put(Context.PROVIDER_URL, url);

returnnew InitialContext(env);

}

privatesynchronizedstaticvoid clean()

{

try

{

serverSocket.close();

}catch(IOException e){e.printStackTrace();}

}

}

[12624 byte] By [Newworld20a] at [2007-11-27 11:43:22]
# 1

Surround the block of code that is causing the error with...try {

//your code

} catch(Exception e) {}

That will stop that error if everything else works.

1cMas5_cowa at 2007-7-29 17:49:36 > top of Java-index,Java Essentials,Java Programming...
# 2

> Surround the block of code that is causing the error

> with...> try {

>//your code

> catch(Exception e) {}

>

> That will stop that error if everything else works.

it is already surrounded with a try{}catch{} block and does handle the error.

The error comes because I'm printing out the stack trace. I'm just trying to figure out a way to keep the occasional problem from happening. It only happens every once and a while, but it causes that request to not be sent back.

Maybe I can explain the situation better as follows:

- Client A sends 4 requests to my server at the same time.

- My server gives each request off to a new thread each with their own new socket to that client.

- If one thread finishes and closes it's connection to the client at the same moment a second thread is doing its own inputstream read it seems to affect it.

The reason this whole thing confuses me a little bit is that I thought since each thread is getting its own socket connection to the client, that when each thread closes its own socket it should not be affecting the other threads. Is it problem that each thread is communicating with the same client?

Newworld20a at 2007-7-29 17:49:36 > top of Java-index,Java Essentials,Java Programming...
# 3

I agree that is possible. That would cause the threads to close. But if it does not affect what you are actually trying to do, then get rid of the printStackTrace(); and just let it pass that error.

does it affect the job it is trying to do?

If not, then don't even worry about it.

1cMas5_cowa at 2007-7-29 17:49:36 > top of Java-index,Java Essentials,Java Programming...
# 4

> does it affect the job it is trying to do?

> If not, then don't even worry about it.

It does affect it, as only 3 of the requests get processes. I guess I could try to have it try to re-open the connection again and try the request again...

Another problem I see that might be going on is that with 4 new socket connections being created all at the same moment is it possible that it is just flooding the socket to the client and one of the threads is actually getting refused from opening a new connection?

If so, is there a good technique to help with this, as I assume this problem must happen somewhat often with people doing similar programs.

Thanks for your guys time

Newworld20a at 2007-7-29 17:49:36 > top of Java-index,Java Essentials,Java Programming...
# 5

Instead of sockets, why don't you use some kind of socket array so you can control the socket connections from one variable?

It is possible it is flooding, in fact some computers can be assigned multiple sockets because they use multiple IP addresses. Did you think of that?

I think you need to do a small scale test using a network simulator and analyze the connections with a packet sniffer like wireshark. Then we can see what's really going on.

Don't take this the wrong way, but do you give out Dukes or just let em sit?

1cMas5_cowa at 2007-7-29 17:49:36 > top of Java-index,Java Essentials,Java Programming...
# 6

> Instead of sockets, why don't you use some kind of

> socket array so you can control the socket

> connections from one variable?

- hmm, I will definitely have to play with this idea

> It is possible it is flooding, in fact some computers

> can be assigned multiple sockets because they use

> multiple IP addresses. Did you think of that?

- very true, no I had not.

> Don't take this the wrong way, but do you give out

> Dukes or just let em sit?

Haha, yea I was about to give them to you. Thanks for the advice. =P

Newworld20a at 2007-7-29 17:49:36 > top of Java-index,Java Essentials,Java Programming...
# 7

Thank you for the stars, I enjoyed helping with this problem.

If you ever need more help, just let me know.

Message was edited by:

1cMas5_cow

1cMas5_cowa at 2007-7-29 17:49:36 > top of Java-index,Java Essentials,Java Programming...