Here's my solution:
*EDIT* ClientApp.java:
package clientapp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ClientApp {
public static class QueueClientThread extends Thread {
private BufferedReader m_in;
public QueueClientThread(BufferedReader in) {
m_in = in;
}
public void run() {
while (true) {
try {
String msg_buf = "\0";
while ((msg_buf = m_in.readLine()) != null) {
System.out.println("Greetings from singlethreaded server: " + msg_buf);
}
} catch (IOException ex) {
Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public static void main(String[] args) {
String hostName = "127.0.0.1";
int portNumber = Integer.parseInt("5056");
try {
Socket clientSocket = new Socket(hostName, portNumber);
PrintWriter outputStream = new PrintWriter(
clientSocket.getOutputStream(), true);
TimerTask clientTask;
clientTask = new TimerTask() {
public void run() {
System.out.println("Sending a message...");
outputStream.println("msg_id: " + Integer.toString(
new Random().nextInt(1000) + 1));
try {
new QueueClientThread(new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()))).start();
} catch (IOException ex) {
Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
new Timer().schedule(clientTask, 200L, 1000L);
} catch (IOException ex) {
Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
*EDIT* MTServer.java:
package mtserver;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MTServer {
public static class QueueClientThread extends Thread {
private BufferedReader m_in;
private PrintWriter m_out;
public QueueClientThread(BufferedReader in, PrintWriter out) {
m_in = in; m_out = out;
}
public void run() {
while (true) {
try {
String msg_buf = "\0";
while ((msg_buf = m_in.readLine()) != null) {
System.out.println("Message sent back to client: " + msg_buf);
m_out.println("Message sent back to client: " + msg_buf);
}
} catch (IOException ex) {
Logger.getLogger(MTServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public static class QueueMTServerThread extends Thread {
private Socket m_Socket;
public QueueMTServerThread(Socket socket) {
m_Socket = socket;
}
public void run() {
try (
PrintWriter out =
new PrintWriter(m_Socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(m_Socket.getInputStream()));
) {
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
String hostName = "127.0.0.1";
int portNumber = Integer.parseInt("5058");
Socket clientSocket = new Socket(hostName, portNumber);
PrintWriter outputStream = new PrintWriter(
clientSocket.getOutputStream(), true);
outputStream.println(inputLine);
new QueueClientThread(new BufferedReader(
new InputStreamReader(clientSocket.getInputStream())), out).start();
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
public static void main(String[] args) throws IOException {
int portNumber = Integer.parseInt("5056");
try {
ServerSocket serverSocket = new ServerSocket(
Integer.parseInt("5056"));
while (true) {
Socket clientSocket = serverSocket.accept();
new QueueMTServerThread(clientSocket).start();
}
} catch (IOException ex) {
Logger.getLogger(MTServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
*EDIT* STServer.java:
package stserver;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
public class STServer {
public static class QueueClientThread extends Thread {
private BufferedReader m_in;
private PrintWriter m_out;
public QueueClientThread(BufferedReader in, PrintWriter out) {
m_in = in; m_out = out;
}
public void run() {
while (true) {
try {
String msg_buf = "\0";
while ((msg_buf = m_in.readLine()) != null) {
System.out.println("Response from singlethreaded server: " + msg_buf);
m_out.println("Response from singlethreaded server: " + msg_buf);
}
} catch (IOException ex) {
Logger.getLogger(STServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public static void main(String[] args) throws IOException {
int portNumber = Integer.parseInt("5058");
ServerSocket serverSocket = new ServerSocket(Integer.parseInt("5058"));
while (true) {
try {
Socket clientSocket = serverSocket.accept();
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
new QueueClientThread(new BufferedReader(
new InputStreamReader(clientSocket.getInputStream())), out).start();
} catch (IOException ex) {
Logger.getLogger(STServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Link to the Oracle's NetBeans Java ready-to-use project:
MTSTServerSocks.zip[
^]
P.S. My solution might at the very first look be rather confusing. I've not left any comments to the fragments of code posted. So, if you've got any questions about this stuff please don't hesitate to give your questions under this topic discussion forum. I'm ready to help you out to understand how to create servers based on various sockets of either multi-client or single-client.
That's all folks. Enjoy.
Arthur.
Quote:
Can I make this project like =>
a message can send from client and it will reply from STserver.
If I've used to know that you need exactly to send response messages from single-threaded server to clients directly, I would have provided this solution much earlier :). However, the proper protocol solution is that each client sends a request message to multithreaded server that immediately forwards the incoming requests to single threaded server, that, in turn, sending response date back to multithreaded server and then it forwarding it back to a specific client. That's the proper and most appropriate solution of this problem.
Now, just in a few words about the code. Normally, this entire code implements a single-threaded server that is much similar to an echo server discussed in
Reading from and Writing to a Socket (The Java™ Tutorials > Custom Networking > All About Sockets)[
^] - Oracle's tutorial for Java sockets and inter-networking. The single-threaded server (e.g. STServer.java) does nothing but receiving incoming messages from socket currently opened and sending response data back to its client. Unlike the multithreaded server it basically accepts only one client per connection being established.
In turn, the multithreaded server accepts multiple incoming clients connections being established. For each of this connection and request being received it typically establishes a single client socket connection to the single-threaded server and feeds the specific request data to it. The single-threaded server receives the request data sent and responses immediately to the multi-threaded server with response data, which is received by multithreaded server's client socket and is redirected to the client's socket accepted by multithreaded server.
A client Java application is mainly based on creating a client socket that will connect to the multithreaded server right after the client app fires a timer event, to send a request message to multithreaded server. Also, the client app implements the functionality for receiving responses from multithreaded server by launching an asynchronous thread, while executing which, the response messages are fetched from the client socket opened.
Let's recall that single- and multithreaded servers, as well as the client app implement almost the same socket functionality for sending and receiving data via the client or server socket being opened. The following code illustrates a socket used to send and receive data from a server for which a connection is established:
public class ClientApp {
public static class QueueClientThread extends Thread {
private BufferedReader m_in;
public QueueClientThread(BufferedReader in) {
m_in = in;
}
public void run() {
while (true) {
try {
String msg_buf = "\0";
while ((msg_buf = m_in.readLine()) != null) {
}
} catch (IOException ex) {
Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public static void main(String[] args) {
String hostName = "127.0.0.1";
int portNumber = Integer.parseInt("5056");
try {
Socket clientSocket = new Socket(hostName, portNumber);
PrintWriter outputStream = new PrintWriter(
clientSocket.getOutputStream(), true);
outputStream.println(some_data);
try {
new QueueClientThread(new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()))).start();
} catch (IOException ex) {
Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
} catch (IOException ex) {
Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
You can use the same concept for implementing the either client's or server's socket functionality.
That's all. Here's my explanation of your problem solution discussed above.
If you've got any questions or comments, just post your message in this topic's forum.
Arthur.
Here's client app's code modification that uses socket and sends a single request message without timer:
public class ClientApp {
public static void main(String[] args) {
String hostName = "127.0.0.1";
int portNumber = Integer.parseInt("5056");
try {
Socket clientSocket = new Socket(hostName, portNumber);
PrintWriter outputStream = new PrintWriter(
clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
System.out.println("Sending a message...");
outputStream.println("msg_id: " + Integer.toString(
new Random().nextInt(1000) + 1));
String msg_buf = in.readLine();
System.out.println("Greetings from singlethreaded server: " + msg_buf);
outputStream.close(); in.close(); clientSocket.close();
} catch (IOException ex) {
Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Enjoy. :).
There's also one improvement and one important tip making the solution even more efficient:
1. To provide a high reliability of multithreaded server let's add messages queueing functionality as follows:
package mtserver;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MTServer {
public static class QueueClientThread extends Thread {
private BufferedReader m_in;
private PrintWriter m_out;
private ArrayList<String> m_MsgsQueue = new ArrayList<String>();
public QueueClientThread(BufferedReader in, PrintWriter out) {
m_in = in; m_out = out;
}
public void run() {
while (true) {
try {
String msg_buf = "\0";
while ((msg_buf = m_in.readLine()) != null) {
System.out.println("Message sent back to client: " + msg_buf);
m_MsgsQueue.add(msg_buf);
for (int index = 0; index < m_MsgsQueue.size(); index++) {
m_out.println("Message sent back to client: " + m_MsgsQueue.get(index));
}
}
} catch (IOException ex) {
Logger.getLogger(MTServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public static class QueueMTServerThread extends Thread {
private Socket m_Socket;
private ArrayList<String> m_MsgsQueue = new ArrayList<String>();
public QueueMTServerThread(Socket socket) {
m_Socket = socket;
}
public void run() {
try (
PrintWriter out =
new PrintWriter(m_Socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(m_Socket.getInputStream()));
) {
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
m_MsgsQueue.add(inputLine);
String hostName = "127.0.0.1";
int portNumber = Integer.parseInt("5058");
Socket clientSocket = new Socket(hostName, portNumber);
PrintWriter outputStream = new PrintWriter(
clientSocket.getOutputStream(), true);
for (int index = 0; index < m_MsgsQueue.size(); index++) {
outputStream.println(m_MsgsQueue.get(index));
}
new QueueClientThread(new BufferedReader(
new InputStreamReader(clientSocket.getInputStream())), out).start();
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
public static void main(String[] args) throws IOException {
int portNumber = Integer.parseInt("5056");
try {
ServerSocket serverSocket = new ServerSocket(
Integer.parseInt("5056"));
while (true) {
Socket clientSocket = serverSocket.accept();
new QueueMTServerThread(clientSocket).start();
}
} catch (IOException ex) {
Logger.getLogger(MTServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
2. To make sure that the solution will work for you when you'll be using it on real servers and not to use virtual machines at the same time, make sure that you will assign different localhost ip addresses (i.e. hostnames). To do this just edit your Windows\System32\drivers\etc\hosts.txt file as follows:
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
# localhost name resolution is handled within DNS itself.
# 127.0.0.1 localhost
# ::1 localhost
127.0.0.1 localhost
127.0.0.2 localhost
127.0.0.3 localhost
After this assign 127.0.0.2:5056 to multithreaded server,
127.0.0.3:5058 for singlethreaded server.
If the solution is working for you after that, then it means that java sockets were used correctly. :)
Here's client app update that receives user input:
ClientApp.java:
package clientapp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ClientApp {
public static void main(String[] args) {
String hostName = "127.0.0.1";
int portNumber = Integer.parseInt("5056");
try {
Socket clientSocket = new Socket(hostName, portNumber);
PrintWriter outputStream = new PrintWriter(
clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
BufferedReader stdIn =
new BufferedReader(new InputStreamReader(System.in));
Boolean done = false;
while (done == false) {
System.out.print("Type in your message /> ");
String userInput = stdIn.readLine();
if (userInput.equals("Quit") || userInput.equals("Exit")) {
done = true; break;
}
System.out.println("Sending a message...");
outputStream.println(userInput);
String msg_buf = in.readLine();
System.out.println("Greetings from singlethreaded server: " + msg_buf);
}
outputStream.close(); in.close(); clientSocket.close();
} catch (IOException ex) {
Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
MTServer.java:
package mtserver;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MTServer {
public static class QueueClientThread extends Thread {
private BufferedReader m_in;
private PrintWriter m_out;
public QueueClientThread(BufferedReader in, PrintWriter out) {
m_in = in; m_out = out;
}
public void run() {
while (true) {
try {
String msg_buf = "\0";
while ((msg_buf = m_in.readLine()) != null) {
System.out.println("Message sent back to client: " + msg_buf);
m_out.println("Message sent back to client: " + msg_buf);
}
} catch (IOException ex) {
Logger.getLogger(MTServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public static class QueueMTServerThread extends Thread {
private Socket m_Socket;
public QueueMTServerThread(Socket socket) {
m_Socket = socket;
}
public void run() {
try (
PrintWriter out =
new PrintWriter(m_Socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(m_Socket.getInputStream()));
) {
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
String hostName = "127.0.0.1";
int portNumber = Integer.parseInt("5058");
Socket clientSocket = new Socket(hostName, portNumber);
PrintWriter outputStream = new PrintWriter(
clientSocket.getOutputStream(), true);
outputStream.println(inputLine);
new QueueClientThread(new BufferedReader(
new InputStreamReader(clientSocket.getInputStream())), out).start();
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
public static void main(String[] args) throws IOException {
int portNumber = Integer.parseInt("5056");
try {
ServerSocket serverSocket = new ServerSocket(
Integer.parseInt("5056"));
while (true) {
Socket clientSocket = serverSocket.accept();
new QueueMTServerThread(clientSocket).start();
}
} catch (IOException ex) {
Logger.getLogger(MTServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}