-2

I'm trying to write an emulator for a single-threaded physical product. It accepts one long-lived connection and any other connections get a single error message (in the same thread).

I know I can use java.net with two threads:

  • Thread 1 - start ServerSocket on port XXXX and wait for accept(). For the first connection create a Socket and Thread #2, and for other connections produce an error message.
  • Thread 2 - process the Socket IO.

But how can I do it with one thread, so it behaves more like the physical product (ie. repeatedly attempting connections would starve the thread from dealing with the first connection)?

Trying not to use third-party libraries, but can do if that's the only option.

Thanks!

Mykro
  • 276
  • 3
  • 11
  • In java you can always leverage the JNI to implement this capability in C to be used by your java program. Because natively this behaviour is garanteed by posix so at least it would work in BSD and GNULinux. https://stackoverflow.com/questions/12861956/is-it-possible-and-safe-to-make-an-accepting-socket-non-blocking – Jan Jun 14 '18 at 07:00
  • Can you give us some information about this single threaded product and the OS it is running? – Jan Jun 14 '18 at 07:04
  • You give not nearly enough information about what exactly you're trying to achieve, and keep dripping additional bits into comments to the answers. – daniu Jun 14 '18 at 07:32
  • @Jan There is no need for JNI here. Java already supports a non-blocking `accept()`. – user207421 Jun 14 '18 at 07:33
  • @daniu As far as I can tell, I'm only restating information that's already given in the post and overlooked by respondents. Happy to add information to the original post if you can let me know what's missing. – Mykro Jun 14 '18 at 08:01
  • What is missing is the part about the error messages to excess clients, for a start. If this is only an emulator why do you need it to be in one thread? What do you care what the internal architecture is? – user207421 Jun 14 '18 at 08:11
  • Does your physical product use a Real Time OS and you want to run embedded Java on there? It would be really nice and to get some background information. You cannot even use user-level threads? – Jan Jun 14 '18 at 08:29

3 Answers3

2

Unfortunately the common java.net.ServerSocket as well as the java.nio.channels.ServerSocketChannel only feature a blocking method to accept incoming connections. However the java.nio package features many other classes and methods to handle I/O-Operations in a single thread by multiplexing the opened channels.

This approach would still enforce a dedicated Thread for the accepting ServerSocketChannel but you could handle every accepted connection in a single thread.

In comparison the ServerSocket approach needs one new thread for each new connection.
Imgaine you connect 100 clients using a ServerSocket then you will end up with 101 thread. With a ServerSocketChannel you could end up using only 2 thread.

Still programming is often about a tradeoff between complexity/flexibility and performance. So keep that in mind.

A possible solution I could think of could look like this:

public static void main( String[] args ) throws IOException
{
  int portNr = 8080;

  ExecutorService es = Executors.newSingleThreadExecutor();
  ChannelHandler ch = new ChannelHandler(); 
  es.execute( ch );

  // Starting server:
  ServerSocketChannel serv = ServerSocketChannel.open();
  // Bind socket to Port
  serv.socket().bind(new InetSocketAddress(portNr));

  while( serverAlive ) 
  {
    ch.addChannel(serv.accept());
  }
  serv.close();
}

How you actually process the new added SocketChannel depends on your application. And so does the ChannelHandler#addChannel method.

L.Spillner
  • 1,772
  • 10
  • 19
  • 3
    `java.nio.channels.ServerSocketChannel` can be put into non-blocking mode, such that its `accept()` method does not block. – user207421 Jun 14 '18 at 07:07
  • And what the solution would look like is non-blocking mode, a `Selector`, and a standard `select()` loop. Nothing like the above. – user207421 Jun 14 '18 at 08:27
  • This answer should be accepted as it is the best way! – Niton Jul 19 '18 at 18:31
0

It seems like you should accept the single connection and then close the ServerSocket. Any future connect attempts will then get a connection refusal. When the long-lived connection ends, create a new ServerSocket, accept one more connection, ... Rinse and repeat.

EDIT If you have to deliver an error message as per your comment below, you have to accept the connection to send it over, and if you have to do I/O and accepting all in one thread you have to use java.nio.channels.ServerSocketChannel/SocketChannel, non-blocking mode, and a Selector.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Thanks, but the future connect attempts need to be given a specific string as the error response (this is to emulate the physical product). This string needs to be generated in the same thread as that which is processing the single connection. – Mykro Jun 14 '18 at 07:16
  • @Mykro OK, see edit. But why does it need to be generated in the same thread? Outside the emulator, who can tell? – user207421 Jun 14 '18 at 08:15
-1

Using a ServerSocket with one Thread is not a good idea at all. WHY?
you know socket.accept() waits till the next client connects, so the Thread is blocked and if you only have one Thread your whole Programm is blocked till a Client connects.
May you explain why you try to do it single threaded?

Niton
  • 189
  • 4
  • 16
  • Hi, thanks for your response. The ServerSocket would have exactly one thread of its own, which is not the application thread, so it wouldn't block the whole program. But as explained in the question, yes, I do want to process all connections in one thread because this is how the physical product functions which I'm trying to emulate. – Mykro Jun 14 '18 at 06:36
  • 1
    @Mykro you will need separate `Thread`s for each of the client connection's IO, but then you can have them all go into a single `Thread` for actual processing. – daniu Jun 14 '18 at 06:47