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();}
}
}

