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
# 2
You didn't even care about readable code formatting. Why do you think someone will care about helping you?
# 3
Honestly, I'm not sure why my code is all f'ed up. How do i do that?
# 4
First try to use code tags.
# 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);
}
}
}
# 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
# 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.
# 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
# 9
I don't care about these lines functionality :)Just tell - which line has number 115?
# 10
Oh, Sorry :)//theManager.processData(line); is the line in question. The exception is thrown on this line,
# 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 );
# 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!
# 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.
# 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..