It's a client server mode. The server uses multi-thread to handle the client request, if a new client request to a particular server, the server will initialize a new thread to handle it. However, I need to add a logic flow to the server thread that it might also need to initialize a request to another server. Basically, the server itself behaves as a server and a client at the same time. It is useful for search, for example, if a client send a search request to a server, and the server doesn't find it in its local file, then it can request to another server to get the result and get back to the client.
I try to implement this by add a request method in the server thread run method, as:
// server thread handle request for client
public void run(){
try{
// input output stream with client
PrintWriter out = new PrintWriter(clnt.getOutputStream(), true);
BufferReader in = new BufferReader( new InputStreamReader( clnt.getInputStream() ) );
...
// try to initial a new request to anther server which is already listening
reqstAntherServ();
...
}
}
The reqstAntherServ method:
public void reqstAntherServ(){
try{
// initial a new socket request
Socket reqstAnthrServ = new Socket(hostname, port);
// input output stream with anther server
PrintWriter out = new PrintWriter(clnt.getOutputStream(), true);
BufferReader in = new BufferReader( new InputStreamReader( clnt.getInputStream() ) );
...
}
}
However, at running time I found that reqstAntherServ method seem does not initial a request successfully, I mean for example server A want to request Server B via the method, the result is that server B which is already listening does not hear any request. Normally, it should print out a message to the console indicating the socket has been created.
Then I thought it might be the thread thing, I guess a server thread can't both keep a communication with the client and initialize a new request at the same time. So I try to put the reqstAntherServ method into anther new thread. Basically, if the server wants to send a request to anther server, it needs to create a new thread which used to handle that. However, it doesn't work either.
I don't know what's the problem or is there another way to implement this mechanism? Thank you!
UPDATED! Include the initial a new thread to put the reqstAnerthServ method, what I tried is to use a static class as thread handler and put the content of reqstAnotherServ method into the run method, as:
private static class ThreadRqstAntherServ implements Runnable {
...
public void run() {
try{
// initial a new socket request
Socket reqstAnthrServ = new Socket(hostname, port);
// input output stream with anther server
PrintWriter out = new PrintWriter(clnt.getOutputStream(), true);
BufferReader in = new BufferReader( new InputStreamReader( clnt.getInputStream() ) );
...
}
}
}
Then in the server thread handler request for client, instead of call the reqstAntherServ method directly, I initial a new thread using the ThreadRqstAntherServ above, as:
// server thread handle request for client
public void run(){
try{
// input output stream with client
PrintWriter out = new PrintWriter(clnt.getOutputStream(), true);
BufferReader in = new BufferReader( new InputStreamReader( clnt.getInputStream() ) );
...
// try to initial a new request to anther server which is already listening
Runnable r = new ThreadRqstAntherServ(...);
Thread t = new Thread(r);
t.start();
...
}
}
Also include the creating server process code, in the main function:
public static void main(String[] args) throws IOException{
try{
ServerSocket serv = new ServerSocket(port);
while (true) {
Socket clnt = serv.accept();
Runnable rServ = new Threadhandler(clnt, ...); // thread handler for the server thread
Thread tServ = new Thread(rServ);
tServ.start();
...
}
}
}
Problem solve, the reason is that since the server socket listens on two ports at the same time, so it needs to use extra thread to handler the second one, otherwise, the communication will be blocked.
Related
A simple version of my server code can be depicted as...
public class Server implements Runnable {
static boolean isFirstClient=false;
...
...
public void run(){
ServerSocket ss=new ServerSocket(port);
while(true){
Socket s= ss.accept();
if(!isFirstClient){
isFirstClient=true;
new ClientHandler(s,true);
}
else{
new ClientHandler(s,false);
}
}
}
...
...
}
Where client handler handles the client and second parameter in the ClientHandler determines whether its the first client or not and sends the packet accordingly to the client. (I wrote a different functionality for first client to register in the server and response from server determines the first Client.)
public class Client implements Runnable(){
boolean iamFirst=false;
public void run(){
InetAddress ip = InetAddress.getByName("localhost");
Socket soc = new Socket(ip, port);
...
// response from server is stored in responsePacket.
...
iamFirst=responsePacket.isFirst();
if(iamFirst){
...
...
}
else{
...
...
}
}
}
But because of large number of clients running at the same time and also use of static variable to detect first client in server it results in running more than 1 client threads as 'firstClient'.
Can anyone suggest the best way to distinguish the first client to register in server keeping in fact that huge number of clients start at the same time?
(Note: I don't want to use sleep() function in the code to seperate one client from other client to simulate a practical scenario.)
You can make isFirstClient volatile; this makes sure all threads see the latest value of the variable.
Another approach would be to synchronise the method where you accept the clients; but since you do that in a loop it would make no sense in this case.
I face this problem in Java.
I have a server class named MyServer and I want to implement a thread pool where each thread runs a method of MyServer when a request comes. I have created another class that implements a server pool named MultiThreadedSocketServer. The class is this:
public class MultiThreadedSocketServer {
public void startServer(MyServer s, int localport, int threadPoolSize) {
final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(threadPoolSize);
Runnable serverTask = new Runnable() {
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(localport);
System.out.println("Waiting for clients to connect...");
while (true) {
Socket clientSocket = serverSocket.accept();
clientProcessingPool.submit(new ClientTask(clientSocket, s));
}
} catch (IOException e) {
System.err.println("Unable to process client request");
e.printStackTrace();
}
}
};
Thread serverThread = new Thread(serverTask);
serverThread.start();
}
}
the class named MultiThreadedSocketServer has an argument named Server s which passes it in client Task class which a thread is created. The client task class is this:
class ClientTask implements Runnable {
private final Socket clientSocket;
private MyServer s;
public ClientTask(Socket clientSocket, MyServer s) {
this.s = s;
this.clientSocket = clientSocket;
}
#Override
public void run() {
System.out.println("Got a client !");
String inputLine = null;
try {
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
// Do whatever required to process the client's request
inputLine = in.readLine();
if (inputLine.equals("Bye")) {
System.out.println("Bye");
System.exit(0);
}
s.handleRequest(inputLine);
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
As you can see when a request comes the handleRequest method of class MyServer is invoked. I want to make this method to run synchronized, meaning only one thread at a time to be able to run this method. Adding synchronized before the method implementation does not achieve anything.
Can anybody give me the proper way to do this?
Thanks in advance for your time.
PS: I added the whole code
MyServer Class
http://pastebin.com/6i2bn5jj
Multithreaded server Class
http://pastebin.com/hzfLJbCS
As it is evident in main I create three requests with handleRequest with arguments Task, task2 and Bye.
The correct output would be
Waiting for clients to connect...
Got a client !
This is an input Task
Request for Task
Got a client !
This is an input task2
Request for task2
Got a client !
This is an input
Bye
But Instead the order is mixed. Sometimes Bye which shuts the server can be executed first. I want to ensure that the order is the one where the requests are created in the main.
But Instead the order is mixed. Sometimes Bye which shuts the server can be executed first. I want to ensure that the order is the one where the requests are created in the main.
You say that you want the server to handle requests in order. This is hard to ensure because you are opening up 3 sockets and writing them to the server but not waiting for any response. This is implementation dependent but I'm not sure there is any guarantee that when the client returns from doing a socket InputStream write, that the server has received the bytes. This means that from the client side, there is no guarantee that the IO completes in the order that you want.
To see if this is the problem, I would remove the System.exit(0) to see if the other lines make it, just after the "Bye" string does. Or you could put a Thread.sleep(5000); before the exit(0).
A simple sort-of fix would be to make sure your PrintStream has auto-flush turned on. That at least will call flush on the socket but even then there are race conditions between the client and the server. If the auto-flush doesn't work then I'd have your client wait for a response from the server. So then the first client would write the first command and wait for the acknowledgement before going to the 2nd command.
In terms of your original question, locking on the server wouldn't help because of the race conditions. The "Bye" might make it first and lock the server fine.
These sorts of questions around how to synchronize the threads in a multi-threaded program really make no sense to me. The whole point of threads is that they run asynchronously in parallel and don't have to operate in any particular order. The more that you force your program to spit out the output in a particular order, the more you are arguing for writing this without any threads.
Hope this helps.
If the problem is that the bye message kills the server before other requests can be handled, one solution could be to not call System.exit(0); on bye.
The bye message could set a flag block further requests from being handled and also notify some other mechanism to call System.exit(0); when the thread pool is idle with no requests left to handle.
am currently working on a project where I have to build a multi thread server. I only started to work with threads so please understand me.
So far I have a class that implements the Runnable object, bellow you can see the code I have for the run method provided by the Runnable object.
public void run() {
while(true) {
try {
clientSocket = serversocket.accept();
for (int i = 0; i < 100; i++) {
DataOutputStream respond = new DataOutputStream(clientSocket.getOutputStream());
respond.writeUTF("Hello World! " + i);
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
//
}
}
} catch(IOException e) {
System.out.println(e.getMessage());
}
}
}
Bellow is the main method that creates a new object of the server class and creates a threat. initializing the Thread.
public static void main(String args[]) {
new Thread(new Server(1234, "", false)).start();
}
I know this creates a new thread but it does not serve multiple clients at once. The first client need to close the connection for the second to be served. How can I make a multi threated server that will serve different client sockets at once? Do I create the thread on the clientSocket = serverSocket.accept();
yes.
from the docs:
Supporting Multiple Clients
To keep the KnockKnockServer example simple, we designed it to listen for and handle a single connection request. However, multiple client requests can come into the same port and, consequently, into the same ServerSocket. Client connection requests are queued at the port, so the server must accept the connections sequentially. However, the server can service them simultaneously through the use of threads—one thread per each client connection.
The basic flow of logic in such a server is this:
while (true) {
accept a connection;
create a thread to deal with the client;
}
The thread reads from and writes to the client connection as necessary.
https://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html
I have setup a simple server and client, where the server waits for the client to send something and then sends a response. But the downside is that both have to listen for the socket to receive something. What if I wanted it to be more flexible in the communication? I was thinking something event-based, so every time the socket received something it'd call a method to handle it, instead of pausing the program to wait for socket.nextLine().
Here's what my server code looks like:
try{
ss = new ServerSocket(port);
s = ss.accept();
in = new Scanner(s.getInputStream());
out = new PrintWriter(s.getOutputStream(), true);
while(!s.isClosed()){
String input = in.nextLine();
handleInput(input);
}
} catch (Exception e){}
And in the handleInput() I send a response to the client.
If you want to be event based with the client doing something when the server sends a packet, then multithread.
Thread t = new Thread(new Runnable() {
public void run() {
someMethod(in.nextLine());
}
});
t.start();
You'd have to make in a field in the enclosing class.
This would cause your program to execute, and when a it receives a packet it would call someMethod().
Of course, this opens up a multitude of problems associated with multithreading, but it's really the only way to do what you want to.
In First class have method "listen" which listening client socket
public void listen() throws IOException {
while (true) {
socket = this.serverSocket.accept();
DataOutputStream out = new DataOutputStream( socket.getOutputStream() );
this.outputStreams.put(socket, out);
Thread miltiServer;
miltiServer = new Thread() {
#Override
public void run() {
InputStream sin = null;
try {
sin = socket.getInputStream();
ObjectInputStream in = new ObjectInputStream(sin);
message = (AgentData) in.readObject();
} catch (ClassNotFoundException ex) {
} catch (IOException ex) {
}
}
};
miltiServer.start();
}
In Second class i need to read and analyze messages which recieved from client socket. I don't know how to get messages in other class. I have idea to use Callable interface, but if i use it, return statement will exit from infinitive cycle.
An easy way for your socket listener to communicate the messages to your Second class is through a BlockingQueue. The listener would read from the socket input stream and call queue.put(...) to add any messages to the queue.
Then the Second class would be in a loop calling queue.take(); which would return each message when it is added to the queue. If you want unlimited messages to be queued then LinkedBlockingQueue would work. If you want to throttle the messages then a bounded queue such as ArrayBlockingQueue might be more appropriate.
Both threads would need to share the same BlockingQueue so you will need to construct it and pass it to both threads or put a method on your Second class named something like addMessage(...) and the BlockingQueue would be inside of your Second class. Then the listener would call second.addMessage(...);.