Socket Server and Threading issues.

Hi Everyone,

I apologize if I'm posting this in the wrong area, but I have a problem with concurrency and this socket TCP server I am working on. The server uses multiple threads so that multiple clients can connect to it. It was working well as a standalone. Then, I added a "manager" class to instantiate the server and the hopefully process any data that is passed to it by clients.

However, when I call a method in the Manager from one of the threads, i get an exception like the following:

Exception in thread "Thread-0" java.lang.NullPointerException

at project.SocketServerConnection.run(SocketServer.java:115)

at java.lang.Thread.run(Unknown Source)

I know my problem has to do with concurrency, but I'm not sure how to solve the problem of calling a method of another object from threads that have been created for a specific client. Any ideas? Also attached is my code.. Search for "//***" to find where my code crashes.

Thanks in Advance!

-K

Message was edited by:

caddik13

Message was edited by:

caddik13

[1099 byte] By [caddik13a] at [2007-11-26 16:48:34]
# 1

Here is the code....

(I can't seem to paste this code properly. Search fortheManager.processData(line); to find the line that the code crashes)

package project;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket;

public class SocketServer {

Manager theManager = null;

ServerSocket echoServer = null;

Socket clientSocket = null;

int numConnections = 0;

int port;

public SocketServer( Manager m, int port ){

this.port = port;

}

public void stopServer() {

System.out.println( "Server cleaning up." );

System.exit(0);

}

public void startServer() {

// Try to open a server socket on the given port

// Note that we can't choose a port less than 1024 if we are not

// privileged users (root)

try {

echoServer = new ServerSocket(port);

}

catch (IOException e) {

System.out.println(e);

}

System.out.println( "Server is started and is waiting for connections." );

// Whenever a connection is received, start a new thread to process the connection

// and wait for the next connection.

while ( true ) {

try{

clientSocket = echoServer.accept();

numConnections ++;

SocketServerConnection oneconnection = new SocketServerConnection(clientSocket, numConnections, this, theManager);

new Thread(oneconnection).start();

}

catch (IOException e){

System.out.println(e);

}

}

}

public void appendLog(String log) {

theManager.appendLog(log);

}

}

class SocketServerConnection implements Runnable {

BufferedReader is;

PrintStream os;

Socket clientSocket;

int id;

SocketServer theServer;

Manager theManager;

public SocketServerConnection(Socket clientSocket, int id, SocketServer server, Manager m){

this.clientSocket = clientSocket;

this.theManager=m;

this.id = id;

this.theServer = server;

System.out.println( "Connection " + id + " established with: " + clientSocket );

//String log = "<connect>"+"\n <id>"+id+"</id>"+"\n <ip>"+clientSocket.getInetAddress()+"

"+"\n</connect>\n";

//server.appendLog(log);

try {

is = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

os = new PrintStream(clientSocket.getOutputStream());

}

catch (IOException e) {

System.out.println(e);

}

}

public void run() {

String line;

try {

boolean serverStop = false;

while (true) {

line = is.readLine();

System.out.println( "Received " + line + " from Connection " + id + "." );

theManager.processData(line);

if (line.equals("kill")) {

serverStop = true;

break;

}

os.println("Server echos: " + line);

}

System.out.println( "Connection " + id + " closed." );

is.close();

os.close();

clientSocket.close();

if ( serverStop ) theServer.stopServer();

}

catch (IOException e) {

System.out.println(e);

}

}

}

Message was edited by:

caddik13

caddik13a at 2007-7-8 23:16:06 > top of Java-index,Core,Core APIs...
# 2
You didn't even care about readable code formatting. Why do you think someone will care about helping you?
Michael.Nazarov@sun.coma at 2007-7-8 23:16:06 > top of Java-index,Core,Core APIs...
# 3
Honestly, I'm not sure why my code is all f'ed up. How do i do that?
caddik13a at 2007-7-8 23:16:06 > top of Java-index,Core,Core APIs...
# 4
First try to use code tags.
Michael.Nazarov@sun.coma at 2007-7-8 23:16:06 > top of Java-index,Core,Core APIs...
# 5

Let's see here....

package project;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.PrintStream;

import java.net.ServerSocket;

import java.net.Socket;

public class SocketServer

{

ServerSocket echoServer = null;

Socket clientSocket = null;

int numConnections = 0;

int port;

//The manager that starts the Socket Server and which I want to be responsible for processing messages etc.

Manager theManager = null;

public SocketServer( Manager m, int port){

this.port = port;

}

public void stopServer()

{

System.out.println( "Server cleaning up." );

System.exit(0);

}

public void startServer()

{

// Try to open a server socket on the given port

// Note that we can't choose a port less than 1024 if we are not

// privileged users (root)

try

{

echoServer = new ServerSocket(port);

}

catch (IOException e)

{

System.out.println(e);

}

System.out.println( "Server is started and is waiting for connections." );

// Whenever a connection is received, start a new thread to process the connection

// and wait for the next connection.

while ( true )

{

try

{

clientSocket = echoServer.accept();

numConnections ++;

SocketServerConnection oneconnection = new SocketServerConnection(clientSocket, numConnections, this, theManager);

new Thread(oneconnection).start();

}

catch (IOException e)

{

System.out.println(e);

}

}

}

public void appendLog(String log) {

theManager.appendLog(log);

}

}

class SocketServerConnection implements Runnable

{

BufferedReader is;

PrintStream os;

Socket clientSocket;

int id;

SocketServer theServer;

Manager theManager;

public SocketServerConnection(Socket clientSocket, int id, SocketServer server, Manager m)

{

this.clientSocket = clientSocket;

this.theManager=m;

this.id = id;

this.theServer = server;

System.out.println( "Connection " + id + " established with: " + clientSocket );

//String log = "<connect>"+"\n <id>"+id+"</id>"+"\n <ip>"+clientSocket.getInetAddress()+"

"+"\n</connect>\n";

//server.appendLog(log);

try

{

is = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

os = new PrintStream(clientSocket.getOutputStream());

}

catch (IOException e)

{

System.out.println(e);

}

}

public void run()

{

String line;

try

{

boolean serverStop = false;

while (true)

{

line = is.readLine();

System.out.println( "Received " + line + " from Connection " + id + "." );

//***I want to process the received data in the Manager class.

//theManager.processData(line);

if (line.equals("shutdown"))

{

serverStop = true;

break;

}

os.println("Server echos: " + line);

}

System.out.println( "Connection " + id + " closed." );

is.close();

os.close();

clientSocket.close();

if ( serverStop ) theServer.stopServer();

}

catch (IOException e)

{

System.out.println(e);

}

}

}

caddik13a at 2007-7-8 23:16:06 > top of Java-index,Core,Core APIs...
# 6
Hey thanks! I do not know why I did not see this before. Sorry about the @#$, I'll get rid of my earlier post
caddik13a at 2007-7-8 23:16:06 > top of Java-index,Core,Core APIs...
# 7
So what is line number 115?this//theManager.processData(line);or thisif (line.equals("shutdown")) ?If first then you did not initialise theManager.If second then you did not read line.
Michael.Nazarov@sun.coma at 2007-7-8 23:16:06 > top of Java-index,Core,Core APIs...
# 8

line.equals(...) checks the string received by a client tcp socket. If this string matches "shutdown", I am able to exit the while(true) loop and then shutdown the server.

In theManager.processData(), I would like to take the data passed to the server via a tcp client, decode the data in the method and then proceed to do something with the data.

I haven't shown the manager class, but right now processData just does the following:

public void processData(String s)

{

System.out.println("The manager received from server: " +s);

}

Soon however, there are going to be a lot of if then cases depending on the string passed.

Also (I think) I initialize theManager in the SocketServerConnection constructor in line 87.

Message was edited by:

caddik13

caddik13a at 2007-7-8 23:16:06 > top of Java-index,Core,Core APIs...
# 9
I don't care about these lines functionality :)Just tell - which line has number 115?
Michael.Nazarov@sun.coma at 2007-7-8 23:16:06 > top of Java-index,Core,Core APIs...
# 10
Oh, Sorry :)//theManager.processData(line); is the line in question. The exception is thrown on this line,
caddik13a at 2007-7-8 23:16:06 > top of Java-index,Core,Core APIs...
# 11

I bet you didn't initialize theManager variable.

Add this code and run application:

if( null == theManager )

System.out.println( "ERROR: theManager is NULL!" );

else

theManager.processData( line );

Michael.Nazarov@sun.coma at 2007-7-8 23:16:06 > top of Java-index,Core,Core APIs...
# 12

You are absolutely correct. I ran the code and I do get the manager is null error. However, OH my goodness, I figured out what happened. I never initialize manager the 1st ever time I receive it in the SocketServer class.

Yes, I am a moron.

But, do you recommend this kind of style? Where I have many threads running, that contact a single thread to perform an action. It just intuitively seems like a bad idea, but i don't know better.....

Thank you so much for catching this though. I am forever grateful!

caddik13a at 2007-7-8 23:16:06 > top of Java-index,Core,Core APIs...
# 13
If you are going to keep number of threads only for managing reading/writing while all other staff still in one place then yes, this is bad idea. You better use nonblocking IO.
Michael.Nazarov@sun.coma at 2007-7-8 23:16:06 > top of Java-index,Core,Core APIs...
# 14

I agree with you. It's not that I will have a number of clients at 1 time (maybe 1-4 at a time) and the chances of a deadlock are rare, but a good initial design will pay off later.

So if the only data i am passing to the manager will be a string, does that mean I will need to import java.nio and then instead of receiving a string, do i need to receive a java.nio.CharBuffer? Or is the implementation more complex than what I am thinking of right now..

caddik13a at 2007-7-8 23:16:06 > top of Java-index,Core,Core APIs...