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!
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.
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.
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?
Related
I'm working on a server/client solution which creates a new server-thread for each client that is connected (adds it to a thread pool). The server-thread waits for a message from the associated client by calling readLine() on the clients sockets input stream. If I set the thread pool to 1 and connect a second client it won't get executed by the thread pool until the first thread is shut down. I was under the impression that a thread pool would automatically idle a thread if it was just waiting on readLine() but I guess that is not the case. How would I go about creating such a program?
This is the server loop which creates new server-threads connected to a client:
private final static Executor executor = Executors.newFixedThreadPool(MAX_CLIENTS);
while (true) {
clientSocket = serverSocket.accept();
executor.execute(new ChatServer(clientSocket, allClients));
}
And the run-method works like this:
socketReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())
while(true) {
inputLine = socketReader.readLine();
//then send input line to all clients
}
As said if the FixedThreadPool is already running MAX_CLIENTS no new clients will get executed.
With Your current design You are going to run out of threads as the number of the the clients goes up. If Your thread pool is size of 20 threads, You cant handle 21 clients simultaneously. Because socket operations are blocking operations.(and Your ChatServer class will keep the executing thread busy with while(true) loop)
You should check AsynchronousSocketChannel and AsynchronousServerSocketChannel classes which support async IO operations. To be able to use these classes You have to change most of Your client server communication logic.
Check out the following links for details and example usage of these classess.
https://www.javaworld.com/article/2853780/socket-programming-for-scalable-systems.html
https://webtide.com/on-jdk-7-asynchronous-io/
I'm in the process of writing a messaging program, and I'm running into a spot where I'm having trouble understanding how to pass a socket over to a new thread for handling outbound messages via TCP. I'm currently using UDP packets for messages coming from a client, to the server, which, being UDP, doesn't require very much processing, as it's simply listening for incoming packets, before it de-serializes the objects, and processes them as needed in a separate thread. My problem now is, I'm setting up a client initiated TCP socket for reverse traffic, from the server to the assorted clients that connect. I've done a bit of research, and I already understood that each client should have their own thread for handling outgoing messages, along with another thread simply for accepting the incoming connections. I'm unsure of how to actually achieve this, and I've done some research into the topic.
I've found this: http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html
The resource above basically verified my original suspicion that this would have to be handled by threads dedicated to the client. They included psuedo code here, which is representing my listener thread.
while (true) {
accept a connection;
create a thread to deal with the client;
}
I'm a bit of a visual learner, and I have been searching for some type of an example where this is done. I'm unsure of what variable I'd be passing over to the thread that keeps the original connection open, and pushes data back to clients. I'm also having a little bit of trouble grasping whether it even keeps the same socket open, or if a new one needs to be established, which then, makes me believe a firewall could interfere, but I know that won't be the case.
Can somebody explain this for me in detail? If possible, an example would be greatly appreciated!
I'll be likely replying and commenting on responses in about 15-30 minutes from the time this is posted.
What you are doing sounds correct. I typically implement a server like this (simplified version with no tracking of the clients and so on):
#Override
public void run() {
//start listening on the port
try {
serverSocket = new ServerSocket(port);
logger.info("Listening for connections on port " + port);
} catch (IOException e) {
logger.error("Cannot start SocketListener on port " + port + ". Stopping.", e);
return;
}
while (!stopped) {
try {
//wait for connection
Socket newSocket = serverSocket.accept();
ClientThread client = new ClientThread(newSocket);
Thread clientThread = new Thread(client, MEANINGFUL_THREAD_ID);
clientThread.start();
} catch ...
}
}
where serverSocket is a ServerSocket instance variable and stopped is a flag I use to stop the listener thread.
So to answer your questions in the comment, you normally pass the Socket object to each client thread so that that thread can work with the input and output stream and handle closing of the socket and so on. Once you "accept" a socket connection, you do not need to recreate the ServerSocket, you simply call .accept() again to start waiting for a new connection.
In most cases, you will need to keep track of all client threads in your server so that you can stop the server gracefully or do broadcasts for example.
Is there a way to check for incoming connections to ServerSocket, so my server would not stop when waiting for someone to connect.
I need something like
try {
if (server.thereisarequest()) {
Socket socket = server.accept();
}
}
Are you sure you want this? Having the code presented, only one thread is waiting. Run another threads which handle accepted connections so that your server doesn't stop.
You can also use java non-blocking asynchronous I/O (nio and nio2), but in the background there is a thread on duty anyway.
Keep it simple... use an infinite while loop to make server look for the incoming request... thats how most of the servers works..
while (true) {
incoming = s.accept(); // incoming is of type Socket.
}
You can create a new thread to accept connections.
Then you have 2 choices:
Process the socket in a new thread
Put the sockets in a queue (ConcurrentLinkedQueue) and check it queue from you main thread.
For work I have written a specialized HTTP server which only performs 301/302/Frame redirections for web sites. Recently, some nefarious clients have been intentionally opening sockets and writing one character every 500 milliseconds in order to defeat my TCP socket timeout. Then they keep the socket open indefinitely and have multiple clients doing the same thing in a distributed denial of service. This eventually exhausts the thread pool which handles the TCP connections. How would you write your code to make it less susceptible to this sort of bad behavior? Here's my socket accept code:
while (true) {
// Blocks while waiting for a new connection
log.debug("Blocking while waiting for a new connection.") ;
try {
Socket server = httpServer.accept() ;
// After receiving a new connection, set the SO_LINGER and SO_TIMEOUT options
server.setReuseAddress(true) ;
server.setSoTimeout(timeout) ;
server.setSoLinger(true, socketTimeout) ;
// Hand off the new socket connection to a worker thread
threadPool.execute(new Worker(cache, server, requests, geoIp)) ;
} catch (IOException e) {
log.error("Unable to accept socket connection.", e) ;
continue ;
}
}
timeout and socketTimeout are currently set to 500 milliseconds.
Start closing sockets after a certain time has passed. If a socket has stayed open too long just close it down. You could do this in two ways:
You could also put a time limit on how long the client takes to send you a request. If they don't sustain a certain level of throughput close em. That can be pretty easy to do in your read loop when your thread is reading the request by adding a System.currentTimeInMillis() at the start and compare to where you are as you loop. If it drifts past a certain limit they are shutdown and dropped.
An alternative idea to this idea is possibly not reject them but let your thread return to the pool, but put the socket on a stack to watch. Let the bytes pile up and after they reached a certain size you can them pass them to a thread in the pool to process. This the hybrid approach to cut em off vs. maybe they aren't bad but slow.
Another way to handle that is watch how long a thread has been working on a request, and if it's not finished within a time limit close the underlying socket. Then the thread will get a SocketException and it can shutdown and clean up.
Here are some other ideas that mostly involve using outside hardware like firewalls, load balancers, etc.
https://security.stackexchange.com/questions/114/what-techniques-do-advanced-firewalls-use-to-protect-againt-dos-ddos/792#792
I am from Ethiopia so i am sorry for my English
I was designing a muiltithread server/client application and the server has its own user interface that keep the list of all connected client the problem is
ss = new ServerSocket( port );
while (true) {
// Grab the next incoming connection
s = ss.accept();
ss.accept(); block the entire process and i am not able to access other functionalities of the server. the user interface of the server completly freez even though the server is accepting new clients and the client side is working perfectly.
so what shall i do to make the server accept new connection while processing other things
There are two (popular) ways of doing this:
A main thread containing a blocking loop waiting for clients. This main thread spawns a new Thread when a client is accepted.
Java New Input/Output. Everything is handled in the main thread. See http://rox-xmlrpc.sourceforge.net/niotut/index.html
Also: you point out your server application has a User Interface. A User Interface should be running in a different thread (the Event Dispatcher Thread, EDT) than the server.
you should spawn thread and call accept there
So Put this Listener ( in a method) and use TaskFactory. TaskFactory will execute the method in a separate thread and you will not have this problem