Link to home
Create AccountLog in
Avatar of funaki01
funaki01

asked on

BindException error with Java NIO server on Tomcat

I have a webapp which starts up a Servlet when the Tomcat server it sits on is started. This Servlet then creates a multi-threaded server which listens for incoming client connections. I originally implented the multi-threaded server using ServerSockets, which I now realise are blocking and aren't going to meet my needs to have several clients connecting at the same time.
I have rooted around and found some code for a multi-threaded server using the Java NIO API and implemented that for my application - I'm now getting "java.net.BindException: Address already in use: bind" errors when the NIO server attempts to bind to the InetAddress and port I provide and it seems as though the Servlet continuosly tries to create the NIO server class over and over.
The previous implementation of my multi-threaded server worked fine and so I'm wondering if my application design is at fault and it's only now becoming apparent??? I've attached a few snippets of the code below, the error occurs at the serverChannel.socket().bind(isa) line.
Servlet startup :
public void init() {
	   if (!initialized) {
		   initialized = initialize();
	   }
   }
   
   protected boolean initialize() {
	   Thread thread = new Thread(this);
	   thread.setDaemon(true);
	   thread.start();
	   return true;
   }
   
   public void run() {
	   boolean stop = false;
 
	   while (!stop) {
		   InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("/alarmSystem.properties");
		   Properties prop = new Properties();
		   try {
			prop.load(in);
			in.close();
		} catch (IOException e) {
			System.out.println("--- Error loading properties ---");
			e.printStackTrace();
		}
		String ServerAddress = prop.getProperty("InterfaceServerAddress");
		String ServerPort = prop.getProperty("InterfaceServerPortNo");
		String dbServerPort = prop.getProperty("DBServerIPAddress");
		String dbName = prop.getProperty("DBName");
 
		new AlarmEventMediator(ServerAddress,ServerPort,dbServerPort,dbName);
		System.out.println("Alarm Servlet started");
	   }
   } 	  	    
 
The NIO server is started from a Mediator class using :
new Thread(new AlarmInterfaceNIOServer(this,serverAddress,Integer.parseInt(serverPort),worker)).start();
 
The NIO Server constructor :
public AlarmInterfaceNIOServer(AlarmEventMediator m, String hostAddress, int port, ServerWorker worker) throws IOException {
		this.hostAddress = hostAddress;
		this.port = port;
		this.selector = this.initSelector();
		this.worker = worker;
		this.med = m;
	}
 
And the initSelector method :
 
private Selector initSelector() throws IOException {
		// Create a new selector
		Selector socketSelector = SelectorProvider.provider().openSelector();
 
		// Create a new non-blocking server socket channel
		this.serverChannel = ServerSocketChannel.open();
		serverChannel.configureBlocking(false);
 
		// Bind the server socket to the specified address and port
		InetSocketAddress isa = new InetSocketAddress(this.hostAddress, this.port);
		serverChannel.socket().bind(isa);
 
		// Register the server socket channel, indicating an interest in 
		// accepting new connections
		serverChannel.register(socketSelector, SelectionKey.OP_ACCEPT);
 
		return socketSelector;
	}

Open in new window

Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Do you have the servlet set to run at startup?
Actually, since you're essentially using a separate TCP/IP app, you would probably find it easier and less error-prone simply to start your server independently of your container.
Avatar of funaki01
funaki01

ASKER

The Servlet is set to auto start (this has been working fine with the other blocking server) - if I don't use this method how can I get the server, which must be on the Tomcat server as it also passes info onto a Flex web client, to start up after the Tomcat server has started??
By executing the command

startup && start-your-server

where the first command is Tomcat's startup script and the second a command to start your own server
I think that option will change entirely my system design and I'd still like to know why i'm getting the Bind error, so although a workaround it doesn't really solve my problem - I can't see anything obvious to explain why one server implementation works and the other doesn't.
I think you need to put some debug code in there to find out when the call to open the Socket occurs
I do have some error checking code in there and the stack trace shows up as below :

Alarm Servlet started
java.net.BindException: Address already in use: bind
      at sun.nio.ch.Net.bind(Native Method)
      at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:119)
      at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:59)
      at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:52)
      at flex.samples.marketdata.AlarmInterfaceNIOServer.initSelector(AlarmInterfaceNIOServer.java:197)
      at flex.samples.marketdata.AlarmInterfaceNIOServer.<init>(AlarmInterfaceNIOServer.java:45)
      at flex.samples.marketdata.AlarmEventMediator.<init>(AlarmEventMediator.java:36)
      at flex.samples.marketdata.AlarmEventMediatorServlet.run(AlarmEventMediatorServlet.java:51)
      at java.lang.Thread.run(Thread.java:619)

After a bit of further investigation (checking that the NIO server actually works as a standalone app which it does) I now think my problems are with the design of my system - using an auto-start Tomcat servlet to then spawn my server doesn't seem to be working. I need the server to react to events initiated by the clients that connect to it, pass on data to the main system and receive data back. The main system will process data from the TCP/IP server and produce a web view in the form of a Flex web app which the Tomcat server hosts. If I make the TCP/IP server a standalone app what is the best way to pass/receive data between the TCP/IP server and the Tomcat server??
>>If I make the TCP/IP server a standalone app ...

Isn't it already stand-alone btw? It might be running in the same vm, but it's still standalone is it not?

Not at the moment as it's wrapped up in the Web App I've deployed to the Tomcat server - that seemed the easiest way to go as I needed to push data pulled from a database to the Flex client, and the data added to the database is from events which are received on the tcp/ip server.
What i'm getting at is this: if you are communicating between the server and Tomcat using TCP/IP, then effectively the two entities are largely independent. I'm suggesting you take that to its logical conclusion and have them entirely independent, in separate VMs
If my conceptual understanding of a Tomcat server is wrong then maybe the TCP/IP server and the Tomcat server are independent, but I don't believe so.
The TCP/IP server is one class (which implements the Runnable interface) alongside several others which are deployed onto the Tomcat server - the auto-start Servlet creates a Mediator object which then creates a DBManager, TCP/IP Server and Feed objects. If I was to extract this functionality into a seperate, standalone application I'd then have to worry about some kind of RMI type communication to the Web Feed part which must sit on a Tomcat server (due to using BlazeDS to allow server push to my Flex client).
Well i was assuming a string-based communcation over TCP/IP is occurring at the moment - perhaps i'm wrong ..?
I think I can see what you are driving at - just make the communication between the Tomcat based app and the standalone TCP/IP server effectively another client connecting to the TCP/IP server??
Would you suggest keeping everything except the Web Feed part of the system seperate to the Tomcat server?
ASKER CERTIFIED SOLUTION
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
Create an account to see this answer
Signing up is free. No credit card required.
Create Account
Still unclear as to why I got the original Bind Exception error but have been pointed in a better direction for the system design so your help was very useful.