So I've created a server and a client for a previous part of the assignment, but now I have to extend/modify the server so that it can handle multiple clients concurrently.
I know I have to do something along the lines of
Server server1 = new Server();
Thread thread = new Thread(server1);
thread.start();
and have the Class Server implement Runnable.
But the lecturers notes on multi-threading are not very clear and I have been starring at this part of the question for a long time and have got no where.
Below is the code I have written for one client at a time to connect to the server.
Any help would be much appreciated.
Server.java
public class Server {
ArrayList<String> tokens = new ArrayList<String>();
private Socket s;
private Scanner in;
private PrintWriter out;
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(1234);
Server serverInstance = new Server();
System.out.println("Server running. Waiting for a client to connect...");
while (true) {
serverInstance.s = server.accept();
System.out.println("Client connected");
serverInstance.run();
System.out.println("Client disconnected. Waiting for a new client to connect...");
}
}
public void start() {
System.out.println("Starting " + threadName);
if (t == null) {
t = new Thread(this, threadName);
t.start();
}
}
public void run() {
try {
try {
in = new Scanner(s.getInputStream());
out = new PrintWriter(s.getOutputStream());
doService(); // the actual service
}
finally {
s.close();
}
}
catch (IOException e) {
System.err.println(e);
}
}
public void doService() throws IOException {
while (true) {
if (!in.hasNext())
return;
String request = in.next();
System.out.println("Request received: " + request);
// (...) test for type of request here (not implemented)
Request(request);
}
}
public void Request(String request) {
String amountStr = in.next();
if (request.startsWith("SUBMIT")) {
if (tokens.size() < 10) {
tokens.add(amountStr);
System.out.println("Token added");
out.println("OK");
}
else {
System.err.println("Error");
out.println("Error");
}
}
else if (request.startsWith("REMOVE")) {
if (tokens.contains(amountStr)) {
tokens.remove(amountStr);
System.out.println("Tokens removed");
out.println("OK");
}
else {
System.err.println("Error");
out.println("Error");
}
}
else if (request.equals("QUIT")) {
System.err.println("Program ended");
out.println("Program ended");
}
tokens.sort(null);
System.out.println(tokens);
out.flush();
}
}
Client.java
public class Client {
public static void main(String[] args) throws IOException {
Socket s = new Socket("localhost", 1234);
InputStream instream = s.getInputStream();
OutputStream outstream = s.getOutputStream();
Scanner in = new Scanner(instream);
PrintWriter out = new PrintWriter(outstream);
String request = "SUBMIT hello \n";
out.print(request);
out.flush();
String response = in.nextLine();
System.out.println("Token: " + response);
s.close();
}
}
What you are trying to duplicate is what RMI has been doing for decades. Java is open source so you can look at how RMI works and learn from there. You can also look on the internet for myriad examples of multi threaded servers with/without RMI.
Related
I'm trying to implement a multi client server program. I decided to implement each client program in a different folder/package. Similarly, the server program will be in a different package. So, when I'm creating a socket on the client side and need to refer to the server, how do i go about it? If the server was on a different computer, I'd provide the IP address.
Socket clientscoket = new Socket("server.java", 2100);
This works when the server program resides in the same directory. What if the server program resides in a different directory?
EDIT:
import java.io.*;
import java.net.*;
import java.util.HashMap;
class ServerSide {
static private HashMap<String, Socket> clientList = new HashMap<String, Socket>();
public static void main(String argv[]) throws Exception {
ServerSide ss = new ServerSide();
new Listener(argv[0]);
}
}
class Listener implements Runnable {
ServerSocket listenSocket;
HashMap<String, Socket> hm = new HashMap<String, Socket>();
Listener(String prt) throws NumberFormatException, IOException {
String output;
listenSocket = new ServerSocket(Integer.parseInt(prt));
Thread t = new Thread(this);
t.start();
}
public Listener() {
// TODO Auto-generated constructor stub
}
// List<Socket> cList = new ArrayList<Socket>();
// Create a new Thread. One for listening. Another for comms
public void run() {
boolean cont = true;
while (cont) {
Socket connectionSocket;
try {
connectionSocket = listenSocket.accept();
new ClientThread(connectionSocket);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* BufferedReader inFromClient = new BufferedReader(new
* InputStreamReader(connectionSocket.getInputStream()));
* System.out.println("Input Stream created"); String cid =
* inFromClient.readLine(); System.out.println(cid+" connected");
* PrintWriter outToClient = new
* PrintWriter(connectionSocket.getOutputStream());
* outToClient.println("Hello "+cid); clientSentence =
* inFromClient.readLine(); welcomeSocket.close(); cont = false;
*
* System.out.println("Received: " + clientSentence);
* capitalizedSentence = clientSentence.toUpperCase() + '\n';
* outToClient.writeBytes(capitalizedSentence);
*/
}
public HashMap<String, Socket> getMap() {
return hm;
}
}
class ClientThread implements Runnable {
String msg;
Thread t;
BufferedReader ipStream;
boolean flag = true;
Listener l = new Listener();
ClientThread(Socket connectionSocket) throws IOException {
System.out.println("We're here");
t = new Thread(this);
ipStream = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
if (ipStream.ready()) {
String cid = ipStream.readLine();
t.setName(cid);
System.out.println(t.getName() + " connected");
l.getMap().put(cid, connectionSocket);
t.start();
}
}
public void run() {
try {
while (flag) {
if (ipStream.ready()) {
System.out.println("Stream ready");
msg = ipStream.readLine();
if (msg.equals("close")) {
System.out.println(t.getName() + " disconnected");
flag = false;
break;
} else {
String[] cmd = msg.split("\\s+");
System.out.println(msg);
if (cmd[0].equals("broadcast")) {
broadcast(cmd[1]);
} else if (cmd[0].equals("unicast")) {
unicast(cmd[1], cmd[2]);
} else if (cmd[0].equals("blockcast"))
blockcast(cmd[1], cmd[2]);
else
continue;
}
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void broadcast(String msg) throws IOException {
for (String k : l.getMap().keySet()) {
if (k.equals(t.getName()))
continue;
Socket receiverSocket = new Socket(l.getMap().get(k).getInetAddress(), l.getMap().get(k).getPort());
PrintWriter outToServer = new PrintWriter(receiverSocket.getOutputStream(), true);
outToServer.println(msg);
}
System.out.println(msg);
}
public void unicast(String cID, String msg) {
System.out.println(msg);
}
public void blockcast(String cID, String msg) {
System.out.println(msg);
}
}
So, when I'm creating a socket on the client side and need to refer to
the server, how do i go about it? If the server was on a different
computer, I'd provide the IP address?
You would need to provide the IP address anyhow, you cannot specify a server using it's class name. You always must specify the host address.
Socket clientscoket = new Socket("server.java", 2100);
What you are doing here, is creating a Socket that binds to the host specified by server.java.
If you need to refer to the server, you should try to connect to the port on which the server listens instead of trying to access it using the class name...
How do you implement it.
You can have port numbers assigned to the type of server in a factory class, that can give you [Server]Sockets when you need them.
Class ConnectionFactory
private static final Map<String, Integer> ports = new HashMap<String, Integer>();
static {
// These Servers would listen to these ports.
ports.put("com.stackoverflow.multiconnect.servers.Server1", 5001);
ports.put("com.stackoverflow.multiconnect.servers.Server2", 5502);
ports.put("com.stackoverflow.multiconnect.servers.Server3", 8080);
}
And you can have instances of both your server and client sockets returned from this class.
public static ServerSocket createServerSocket(Class<?> serverClass)
throws IOException {
return createServerSocket(serverClass.getName());
}
public static ServerSocket createServerSocket(String fqcn)
throws IOException {
Integer port = ports.get(fqcn);
if (port == null)
throw new IllegalArgumentException("No server registery found for " + fqcn);
return new ServerSocket(port);
}
public static Socket createClientSocket(Class<?> serverClass)
throws UnknownHostException, IOException {
return createClientSocket(serverClass.getName());
}
public static Socket createClientSocket(String fqcn)
throws UnknownHostException, IOException {
Integer port = ports.get(fqcn);
if (port == null)
throw new IllegalArgumentException("No server registery found for " + fqcn);
return new Socket("localhost", port);
}
Now with this, you can:
//Open a server Socket
ServerSocket server1 = ConnectionFactory.createServerSocket(Server1.class);
// Create a client to connect to a server
Socket client1 = ConnectionFactory.createClientSocket(Server1.class);
A more elaborate and full example could be found here.
Try instead of server.java making use of the whole path of the directory to server.java
So home/user/class/server/server.java
I have one TCP-Client and one TCP-Server written in Java. The Server is waiting for instructions from the Client but should also be able to send instructions to the client.
I can make the Client send something to the Server and wait for a reply. But I can not make it like waiting for a message without sending something before.
TCP-Client
public class TCPClient {
static DataOutputStream toServer;
static BufferedReader fromServer;
static Socket socket;
public static void main(String[] args) throws Exception {
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
System.out.println("*************************");
System.out.println("* Client *");
System.out.println("*************************");
System.out.println("INSTRUCTION | EFFECT");
System.out.println("aktiv | ready to do something");
System.out.println("exit | disconnect");
System.out.println();
System.out.print("Please enter the IP-Address of the Server: ");
String ip = input.readLine();
System.out.println();
try {
socket = new Socket(ip, 9999);
} catch (Exception e) {
System.out.println("Can not connect to Server!");
}
toServer = new DataOutputStream(socket.getOutputStream()); // Datastream FROM Server
fromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (sendRequest()) {
receiveResponse();
}
socket.close();
toServer.close();
fromServer.close();
}
private static boolean sendRequest() throws IOException {
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String line;
boolean holdTheLine = true; // Connection exists
System.out.print("> ");
line = input.readLine();
switch (line) {
case "aktiv":
toServer.writeBytes("active" + '\n');
break;
case "exit":
holdTheLine = false;
break;
default:
break;
}
return holdTheLine;
}
private static void receiveResponse() throws IOException {
System.out.println("Server: " + fromServer.readLine() + '\n');
}
}
TCP-Server
public class TCPServer {
static boolean connected = true;
public static void main(String[] args) throws Exception {
System.out.println("********************************");
System.out.println("* Server *");
System.out.println("********************************");
System.out.println("INSTRUCTION | EFFECT");
System.out.println("ok | send an ok to client");
ServerSocket listenSocket = new ServerSocket(9999);
while (true) {
final Socket client = listenSocket.accept();
Thread newClientThread = new Thread(new Runnable() {
#Override
public void run() {
multithreadedServer(client);
}
});
newClientThread.start();
}
}
public static void multithreadedServer(Socket client) {
String line;
final BufferedReader fromClient;
final DataOutputStream toClient;
Thread cmdForClient;
try {
fromClient = new BufferedReader(new InputStreamReader(client.getInputStream()));
toClient = new DataOutputStream(client.getOutputStream());
while (connected) {
cmdForClient = new Thread(new Runnable() {
#Override
public void run() {
try {
String line = fromClient.readLine();
System.out.println("Client: " + line);
if (line.equals("exit")) {
connected = false;
}
} catch (Exception e) {
System.out.println(e);
}
}
});
cmdForClient.start();
final BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
try {
String reply = input.readLine();
if (reply.equals("ok")) {
toClient.writeBytes("OK." + '\n');
}
} catch (Exception e) {
System.out.println(e);
}
}
fromClient.close();
toClient.close();
client.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
The typical operation for a client-server scenario is for the client sending requests to the server. However, in peer to peer applications, both endpoints might act as both clients and servers. The only difference would be which endpoint that opened the connection. In your case, the problem is that only the "server" is using a receiver thread. Start a receiver thread at the client side and your problem should be solved. You should pretty much be able to just reuse your threaded code from the server in the client. Just pass the socket to the receive thread after opening the connection to the server.
EDIT:
In your client:
Thread newServerThread = new Thread(new Runnable() {
#Override
public void run() {
multithreadedServer(socket);
}
});
newServerThread.start();
where socket, is the socket to the server. You may need to update multithreadedServer for any specifics or differences for the clients operations, but the principle should be the same.
I need to convert this single threaded Server in Multi Threaded one, so i'm able to handle multiple request from a server:
public class YASGP {
public static void main(String args[]) throws IOException {
ServerSocket server;
try{
server = new ServerSocket(5559);
System.out.println("Listening for connection on port 5559 ....");
while (true) {
Socket clientSocket = server.accept();
InputStreamReader isr = new InputStreamReader(clientSocket.getInputStream());
BufferedReader reader = new BufferedReader(isr);
String line = reader.readLine();
new Thread(new WorkerRunnable(clientSocket)).start();
while (!line.isEmpty()) {
System.out.println("----- " + line);
if (!line.contains("OPTIONS")) {
// System.out.println("Non c'รจ nulla!!!");
} else {
timeS = line.substring(line.indexOf("timeS=") + 6, line.indexOf("&url"));
url = line.substring(line.indexOf("url=") + 4, line.lastIndexOf("¶m"));
param = line.substring(line.indexOf("¶m=") + 7, line.indexOf("HTTP"));
}
line = reader.readLine();
}
}
}
}catch (IOException e) {
System.out.println("Could not listen on port: 4001");
}
}
private static class RequestHandlingClass {
public RequestHandlingClass(Socket clientSocket) {
}
}
}
How i can convert it? Thanks to all
remove the 'client processing' code from the server as follows
public static void main(String args[]) throws IOException {
ServerSocket server;
try{
server = new ServerSocket(5559);
System.out.println("Listening for connection on port 5559 ....");
while (true) {
Socket clientSocket = server.accept();
new Thread(new WorkerRunnable(clientSocket)).start();
}
}catch (IOException e) {
System.out.println("Could not listen on port: 4001");
}
}
then the code that you lifted out goes in to the run method of the workerRunnable class .
I recommend u use the excutorService api.Since it will manager all your threading issue for u behind the scene
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
//Your code here
});
I'm trying to create a proxy application, but I'm facing problems in server socket. The Server Socket is not accepting the connection and returning a socket. Hence, I cannot test the proxy application. What is wrong?
The problem line is indicated in WebServe.java:
public class WebServe implements Runnable {
Socket soc;
OutputStream os;
BufferedReader is;
String resource;
WebServe(Socket s) throws IOException {
soc = s;
os = soc.getOutputStream();
is = new BufferedReader(new InputStreamReader(soc.getInputStream()));
}
public void run() {
System.err.println("Running");
getRequest();
returnResponse();
close();
}
public static void main(String args[]) {
try {
System.out.println("Proxy Thread");
ServerSocket s = new ServerSocket(8080);
for (;;) {
s.setSoTimeout(10000);
WebServe w = new WebServe(s.accept()); // Problem is here
Thread thr = new Thread(w);
thr.start();
w.getRequest();
w.returnResponse();
w.close();
}
} catch (IOException i) {
System.err.println("IOException in Server");
}
}
void getRequest() {
System.out.println("Getting Request");
try {
String message;
while ((message = is.readLine()) != null) {
if (message.equals("")) {
break;
}
System.err.println(message);
StringTokenizer t = new StringTokenizer(message);
String token = t.nextToken();
if (token.equals("GET")) {
resource = t.nextToken();
}
}
} catch (IOException e) {
System.err.println("Error receiving Web request");
}
}
void returnResponse() {
int c;
try {
FileInputStream f = new FileInputStream("." + resource);
while ((c = f.read()) != -1) {
os.write(c);
}
f.close();
} catch (IOException e) {
System.err.println("IOException is reading in web");
}
}
public void close() {
try {
is.close();
os.close();
soc.close();
} catch (IOException e) {
System.err.println("IOException in closing connection");
}
}
}
public static void main(String args[]){
try {
System.out.println("Proxy Thread");
ServerSocket s = new ServerSocket (8080);
for (;;){
s.setSoTimeout(10000);
Move that ahead of the loop. You don't need to keep setting it. You don't really need it at all actually.
WebServe w = new WebServe (s.accept()); //Problem is here
The problem is here only because you set a socket timeout you don't actually need.
Thread thr = new Thread (w);
thr.start();
So far so good.
w.getRequest();
w.returnResponse();
w.close();
Remove. The next problem is here. The run() method of WebServ already does this.
As to the rest, you aren't writing an HTTP header in the response.
I have 2 classes, a server and a client. The server uses multiple threads to accept many clients. So x clients can join the same server. However in an attempt to identify the threads from the client method, I seem to have found that its not making multiple threads as the ID are the same for all clients. The code I have is as follows:
SERVER:
public class Server
{
ServerSocket serverSocket;
int portNumber;
public static volatile String userInput;
public volatile int noOfClients = 0;
public static void main(String[] args)
{
Server s = new Server();
s.startup();
}
/**
* Start the server on the user picked port
*/
public void startup()
{
try
{
System.out.println("Enter a port");
Scanner dif = new Scanner(System.in);
portNumber = Integer.parseInt(dif.nextLine());
dif.close();
serverSocket = new ServerSocket(portNumber);
newThread();
}
catch (IOException e) {
System.out.println("Error");
System.exit(0);
}
}
public void newThread()
{
Thread thread =new Thread()
{
public void run()
{
while(true) {
try {
accept();
} catch (Exception e) {
System.out.println("Error");
}
}
}
};
thread.start();
}
public void accept()
{
try
{
Socket clientSocket = serverSocket.accept();
new Thread(new ClientSocket(clientSocket)).start();
System.out.println("A new client has just connected.");
noOfClients++;
} catch(IOException e)
{
System.out.println("Error");
System.exit(0);
}
}
class ClientSocket implements Runnable {
Socket clientSocket;
public ClientSocket(Socket clientSocket) {
this.clientSocket = clientSocket;
}
public void run() {
{
try
{
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while (true)
{
userInput = in.readLine();
}
} catch (IOException e)
{
System.out.println("Error");
}
}
}
}
}
CLIENT:
public class Client
{
Socket clientSocket;
public static int threadName;
public static void main(String[] args) throws IOException {
String hostName = args[0];
int portNumber = Integer.parseInt(args[1]);
try {
Socket serverSocket = new Socket(hostName, portNumber);
PrintWriter out = new PrintWriter(serverSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
Thread thread = Thread.currentThread();
System.out.println("RunnableJob is being run by " + thread.getName() + " (" + thread.getId() + ")");
String userInput;
while ((userInput = stdIn.readLine()) != null)
{
out.println(userInput);
System.out.println("Server: " + userInput);
}
} catch(UnknownHostException e) {
System.out.println("error in host");
} catch(IOException e) {
System.out.println("error in IO");
}
}
}
When running two separate clients, the
System.out.println("RunnableJob is being run by " + thread.getName() + " (" + thread.getId() + ")");
line of code prints out the same. How can i fix it so that each new client connection is started within is own UNIQUE thread. so 2 clients will have 2 threads in total? Thanks :)
First, you are checking the thread ids for the clients, which are separate from each other, so that won't work.
However using a thread id is not a very good way to identify clients. Instead why don'y you keep a count of the number of clients, then when a new one joins, increment the number and give the client object that number as an id.
Multiple clients will connect at different port no with server. You can use that port no to distinguish between clients.
You can store ClientSocket some where to retrieve other information of each client in future if needed as shown in below code.
Here is the code:
private static HashMap<Integer, ClientSocket> clientInfo = new HashMap<Integer, ClientSocket>();
class ClientSocket implements Runnable {
Socket clientSocket;
public ClientSocket(Socket clientSocket) {
this.clientSocket = clientSocket;
System.out.println(clientSocket.getPort());
clientInfo.put(clientSocket.getPort(), this);
}
...
Read more about Java Server with Multiclient communication.