(Java) Getting two threads to communicate with each other whilst running? - java

I'm learning java. I'm trying to make a simple client/server chat system. What I have so far is a program where the server accepts multiple client connections by giving them each a seperate thread.
My problem now, is that I can't figure out how to get an input from one client, and then have it be sent amongst all of the clients, thus essentially have a very very simple chat mechanic. How would I go about accomplishing this? What would be the simpler way?
My code so far is here;
class Client {
public static void main(String argv[]) throws Exception {
String sentMessage; //variable for input
String receivedMessage; //variable for output
String status;
boolean running;
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
Socket clientSocket = new Socket("127.0.0.1", 5622); //name of computer to connect with and port number to use
DataOutputStream outToServer =
new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer =
new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
System.out.println("Client Side\n");
running = true;
while(running)
{
sentMessage = inFromUser.readLine(); //user inputs text to variable 'xInput'
outToServer.writeBytes(sentMessage + '\n'); //the variable is sent to the server
status = inFromServer.readLine();
System.out.println("FROM SERVER: " + status); //display to user
}
clientSocket.close();
}
}
The server code.
class Server {
public static void main(String argv[]) throws Exception {
String clientMessage;
boolean listening = true;
int portNumber = 5622;
try (ServerSocket serverSocket = new ServerSocket(portNumber)) {
while (listening) {
new ServerThread(serverSocket.accept()).start();
}
} catch (IOException e) {
System.err.println("Could not listen on port " + portNumber);
System.exit(-1);
}
}
}
The thread that handles the client connections.
public class ServerThread extends Thread {
private Socket socket = null;
public ServerThread(Socket socket) {
super("ServerThread");
this.socket = socket;
}
public void run () {
int msgCnt = 0;
try (
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
) {
//something needs to go here
} catch (IOException e) {
e.printStackTrace();
}
}

If you are looking for a simple client-server communication samples then please have a look at below posts where I have described it step by step.
Multiple clients access the server concurrently
Java Server with Multiclient communication.

Related

Is this the correct way to implement multithreading on Server side of concurrent client/server setup?

I have created this code snippet in both a single threaded version and multithreaded for a client/server setup I have going. I have tested both (recording the avg turn around time) and have gotten EXTREMELY similar results within margin of error when running multiple simple server commands at once. have I implememnted my client handler wrong?
This is my first time trying to implement a multithreaded server and from my understanding it just a matter of putting in a client handler being
`
class ServerThread extends Thread {
private Socket socket;
public ServerThread(Socket socket) {
this.socket = socket;
}
`
below is the snippet of the whole server code.
`
public class Server {
public static void main(String[] args) {
if (args.length < 1) return;
int port = Integer.parseInt(args[0]);
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("Server is listening on port " + port);
while (true) {
Socket socket = serverSocket.accept();
System.out.println("New client connected");
new ServerThread(socket).start();
}
} catch (IOException ex) {
System.out.println("Server exception: " + ex.getMessage());
ex.printStackTrace();
}
}
}
class ServerThread extends Thread {
private Socket socket;
public ServerThread(Socket socket) {
this.socket = socket;
}
public void run() {
try {
InputStream input = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
OutputStream output = socket.getOutputStream();
PrintWriter writer = new PrintWriter(output, true);
String text;
do {
text = reader.readLine(); // reads text from client
Process p = Runtime.getRuntime().exec(text);
BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));
String outputLine;
while ((outputLine = stdout.readLine()) != null) { // while serverMsg is not empty keep printing
writer.println(outputLine);
}
stdout.close();
writer.println("ENDCMD");
// Text here should just write back directly what the server is reading...?
}
while (!text.toLowerCase().equals("exit"));
socket.close();
} catch (IOException ex) {
System.out.println("Server exception: " + ex.getMessage());
ex.printStackTrace();
}
}
}
`
I have tested both (recording the avg turn around time) and have gotten EXTREMELY similar results within margin of error when running multiple simple server commands at once. have I implememnted my client handler wrong?
If you are not making a new connection for each command that you send, then this would be expected. Since each connection runs on one thread, a multi-threaded approach, as you have shown, would have the same speed as if you didn't make a new thread for each connection. The difference is that, without multi-threading, you can only have one connection at a time.

Server doesn't listen to requests

as a part of my homework I have to build two classes one listener and one that is making the requests to the server (the server is already written by my teacher and I don't know how code looks like). In theory: The server that I'm connected to should reply with the exact same requests I sent to him. But in practice I get nothing back.
public class Listenerthread extends Thread {
Socket s;
Scanner answerServer;
public Listenerthread(Socket socket) {
this.s = socket;
this.answerServer = new Scanner(new BufferedReader(new InputStreamReader(s.getInputStream())));
}
public void run() {
System.out.println("Listening to the responses from the server......");
while (true) {
if (answerServer.hasNext()) {
System.out.println(answerServer.nextLine());
}
}
}
}
public class Mainthread {
public static void main(String[] args) throws ParseException {
Socket s = new Socket("someServer", 9999);
Listenerthread server = new Listenerthread(s);
server.start();
if (s.isConnected()) {
System.out.println("Connected");
}
String req = "Heyyy mate"; // server should sent me this back
PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
pw.println(req);
pw.flush();
//pw.close();
//s.close();
}
}
Update: A comment that OP left on the question after I started writing this answer shows that OP does not actually need to handle the server side of the communications. I will leave this answer for now in case it could still be useful.
When you have a client/server model, you should use a ServerSocket on the server side, as you alluded to in your question but then do not appear to have done in your code.
ServerSocket
Here is a ServerSocket example that may clear that up.
ServerSocket serverSocket;
public void serverSocketTest()
{
serverSocket = new ServerSocket(9999);
// each of the below methods will happen on separate threads
new Thread(this::serverSideAcceptConnectionFromClient).start();
new Thread(this::clientSideConnectToServer).start();
}
public void clientSideConnectToServer()
{
try {
System.out.println("Client is trying to connect to server...");
Socket connectionToServer = new Socket("localhost", 9999);
OutputStream thisGoesToTheServer = connectionToServer.getOutputStream();
InputStream thisIsDataComingFromServer = connectionToServer.getInputStream();
System.out.println("Client successfully connected to server.");
} catch(IOException ex) {
System.out.println("Connection to server failed. (" + ex + ")");
}
}
public void serverSideAcceptConnectionFromClient()
{
try {
System.out.println("Server is listening for potential clients...");
Socket connectionFromClient = serverSocket.accept();
InputStream thisIsDataComingFromClient = connectionFromClient.getInputStream();
OutputStream thisIsGoesBackOutToClient = connectionFromClient.getOutputStream();
System.out.println("Server accepted a client");
} catch(IOException ex) {
System.out.println("Error while listening for clients. (" + ex + ")");
}
}

Java - How do I loop to read the InputStream until the user makes an input to continue?

I have a multithreaded client-server system which works back and forth with the client communicating first and the server replying.
However, for two specific clients, I need them to constantly check if there is data held in the input stream before proceeding when the user makes an input.
The program is a car park management system. When the car park is full(0 spaces available) and a car arrives at an entrance client, the system forms a queue of clients waiting to grant entry. When a car leaves the car park, the first client in the queue is removed and added to a BlockingQueue for that specific entrance client. I have created a direct output output stream for each of the entrance clients. So when a BlockingQueue is not empty, data is taken from this queue and output is sent to the stream of that specific client.
However, the problem is - the entrance client which was queued should automatically read its InputStream and print the data to grant access, but instead it causes an error and crashes. I think what is happening is that when the system first starts, the is the client is stuck waiting to read data which initially doesn't exist because it would require some sort of input at the first stage, causing an error.
How do I fix this so that the client reads and prints the input stream(whether it be specific data such as contains the word "queue") IF there is data available else to continue IF the user makes an input.
I hope this makes sense, I tried to make it as clear as possible.
Server class:
public class Server {
public static void main(String[] args) throws IOException {
//Create the shared objects in the global scope...
int groundFloor = 0; //SET TO 0 FOR TESTING
int firstFloor = 0;
SharedState SharedStateObject = new SharedState(groundFloor,firstFloor);
//Sets up the server socket on port 4444
ServerSocket serverSocket = null;
try
{
serverSocket = new ServerSocket(4444);
System.out.println("Car Park Server started." + "\n");
}
catch (IOException e) {
System.err.println("Could not start server on specified port.");
System.exit(-1);
}
//Got to do this in the correct order with only four clients!
ServerThread GroundFloorEntrance = new ServerThread(serverSocket.accept(), "GroundFloorEntrance", SharedStateObject);
ServerThread FirstFloorEntrance = new ServerThread(serverSocket.accept(), "FirstFloorEntrance", SharedStateObject);
ServerThread GroundFloorExit1 = new ServerThread(serverSocket.accept(), "GroundFloorExit1", SharedStateObject);
ServerThread GroundFloorExit2 = new ServerThread(serverSocket.accept(), "GroundFloorExit2", SharedStateObject);
GroundFloorEntrance.start();
FirstFloorEntrance.start();
GroundFloorExit1.start();
GroundFloorExit2.start();
serverSocket.close();
//Loop for granting queued clients access
while(true)
{
BlockingQueue<String> queuedGroundAccess = SharedStateObject.getQueuedGround();
BlockingQueue<String> queuedFirstAccess = SharedStateObject.getQueuedFirst();
if(!queuedGroundAccess.isEmpty())
{
Socket clientSocket = GroundFloorEntrance.clientSocket();
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
try
{
out.println(queuedGroundAccess.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(!queuedFirstAccess.isEmpty())
{
Socket clientSocket = FirstFloorEntrance.clientSocket();
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
try
{
out.println(queuedFirstAccess.take());
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}
Client
public class GroundFloorEntrance {
#SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
// Set up the socket, in and out variables
Socket clientSocket = null;
PrintWriter out = null;
BufferedReader in = null;
int port = 4444;
String serverName = "localhost";
String clientID = "Ground Floor Entrance";
try {
clientSocket = new Socket(serverName, port);
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host: " + serverName);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to: "+ port);
System.exit(1);
}
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String fromServer = null;
String fromUser = null;
System.out.println("Initialised " + clientID + " client and IO connections");
//I THINK THE ISSUE IN THE FOLLOWING STRUCTURE:
while (true) {
fromServer = in.readLine();
if(fromServer != null && fromServer.contains("Queue: "))
{
System.out.println(fromServer);
}
fromUser = stdIn.readLine();
if (fromUser != null) {
out.println(fromUser);
}
fromServer = in.readLine();
System.out.println(fromServer);
}
}
}
A problem is in this loop. When you write fromServer = in.readLine(); it stop execution of your program and waits for data to be entered from server.
while (true) {
fromServer = in.readLine();
if(fromServer != null && fromServer.contains("Queue: "))
{
System.out.println(fromServer);
}
fromUser = stdIn.readLine();
if (fromUser != null) {
out.println(fromUser);
}
fromServer = in.readLine();
System.out.println(fromServer);
}
What you can do with that? You should read data from server in another thread to prevent blocking main thread while waiting for data. Like that:
new Thread(new MyRunnable(fromServer)).start();
And MyRunnable will look like this:
public class MyRunnable implements Runnable {
private Scanner scanner;
public MyRunnable(Scanner scanner) {
this.scanner = scanner;
}
#Override
public void run() {
while (true) {
if (scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
}
}
}
If you will have some questions, please ask.

Issues with Java Client<-->Server Socket

This is what I want to achieve:
There are client and server sockets. The client socket will send a message to the server (for instance "add:2:3" to add 2 and 3, etc). The server should response with an answer. When the answer arrives, the client can send additional message (like "subtract:5:8" to subtract 5 from 8), etc... Thus the client will send a message, then it will get a response, then it will send the next message and get a response, etc. Am sending the message from the command line.
This is what I have now but it is not working:
// Server code
public class MT extends Thread{
private Socket sock;
private BufferedReader rd;
private OutputStreamWriter wr;
private Client client;
public MT(Socket sock) throws IOException {
this.sock= sock;
rd = new BufferedReader(new InputStreamReader(sock.getInputStream()));
wr = new OutputStreamWriter(sock.getOutputStream());
wr.write("You are welcome" + "\n");
wr.flush();
}
public void run(){
try{
while(true){
String command = reader.readLine();
// Will process data here and then send results to client
// At the moment i just want to send the message back to client
wr.write(command + "\n"); // send results to client
}
}
}
}catch(IOException ex){
System.err.println("Problem reading data from client");
}
}
}
public class MyServio {
public static void main(String[] args) {
try(ServerSocket server = new ServerSocket()){
server.bind(new InetSocketAddress("0.0.0.0", 4444));
System.out.println("Listening...");
try{
while(true){
Socket con = server.accept();
Thread a = new MT(con);
a.start();
}
}catch(IOException ex){
System.err.println("Problem...");
}
}catch(IOException ex){
System.err.println("Server Issues");
}
}
}
// Client
For the client I decided to use two threads to read and write to the server
public class MyRead extends Thread{
private BufferedReader r;
public ReadFromServer(BufferedReader r){
this.r = r;
}
#Override
public void run() {
StringBuilder m = new StringBuilder();
try {
while(true){
message.append(r.readLine());
System.out.println(m);
}
} catch (IOException e) {
System.out.println("Problem in MyRead");
e.printStackTrace();
}
}
}
public class MyWrite extends Thread{
private OutputStreamWriter w;
Scanner sc;
public WriteToServer(OutputStreamWriter w){
this.w = w;
sc = new Scanner(System.in);
}
#Override
public void run() {
try {
while(true){
System.out.print("Type message: ");
String msg = sc.nextLine();
w.write(msg + "\n");
w.flush();
}
} catch (IOException e) {
System.out.println("Problem in MyWrite");
e.printStackTrace();
}
}
}
public class CSock {
private OutputStreamWriter w;
private BufferedReader r;
public ClientSocket() {}
public void do(){
InetAddress ad = null;
try {
ad = InetAddress.getByName("127.0.0.1");
} catch (UnknownHostException e) {
System.err.println("Error InetAddress");
}
try (Socket s = new Socket(addr, PORT)) {
System.out.println("Server connecting...");
StringBuilder message = new StringBuilder();
r = new BufferedReader(new InputStreamReader(s.getInputStream()));
w = new OutputStreamWriter(s.getOutputStream());
message.append(r.readLine()); // reads the welcome message from server
System.out.println(message);
// I start the read and write threads so that the client can read and write message to the server
ReadFromServer rd = new ReadFromServer(r);
WriteToServer wt = new WriteToServer(w);
rd.start();
wt.start();
} catch (IOException ex) {
System.err.println("problem connecting to server");
}
}
}
public class Main {
public static void main(String[] args){
ClientSocket clientSocket = new ClientSocket();
clientSocket.do();
}
}
I start the server first, and then I start the client, but the client gives an exception:
Problem in MyRead
java.net.SocketException: socket closed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:170)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at model.ReadFromServer.run(ReadFromServer.java:31)
The last line in the exception indicates that message.append(reader.readLine()); in the code is the problem. I don't close sockets or input stream or output stream anywhere in my code, yet I get this exception.
Also get similar socket closed exception in the MyWrite class in the run() method in the following line writer.flush();
In the client on this line
try (Socket s = new Socket(addr, PORT)) {
You're telling the jvm that it should close the socket after executing the try statement.
This line is creating a reader from the output stream of the socket.
r = new BufferedReader(new InputStreamReader(s.getInputStream()));
And this is creating a functionality that read from server.
ReadFromServer rd = new ReadFromServer(r);
ReadFromServer is a thread, and it's free to execute after the try-catch statement has finished. So when it execute reader.readLine() the socket is closed.
You closed the socket and then continued to use it. The try-with-resource statement closed the socket; the two threads you started continued to use it.

Can't send multiple messages via socket

I'm trying to make a little chat system. I have a console and a client. Right now only the client need to send messages to the console. I can connect successfully to the server, and i can send one message from client to console. The trouble begins after sending the first message. When the first message i can't send any other messages.
I don't know if it's the console that won't read the message or the client that won't send the message. In this case how could i troubleshoot this?
public class ClientMainClass {
private static Socket socket;
public static void main(String args[]) {
try {
String host = "localhost";
int port = 25000;
InetAddress address = InetAddress.getByName(host);
socket = new Socket(address, port);
Scanner scanner = new Scanner(System.in);
System.out.println("Skriv dit username:");
String name = scanner.nextLine();
System.out.println("Du er logget ind som: " + name);
String input;
do{
input = scanner.nextLine();
if (input.equalsIgnoreCase("exit")) {
System.out.println("Du forlod serveren");
socket.close();
continue;
}else {
/*OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);*/
PrintWriter printWriter = new PrintWriter(socket.getOutputStream(),true);
Date date = new Date();
String time = date.getDate()+"/"+date.getMonth()+":"+date.getHours()+":"+date.getMinutes();
//Send the message to the server
String message = time+ " - " + name + ": "+input;
printWriter.println(message);
System.out.println(message);
continue;
}
}while (!(input.equals("exit")));
} catch (Exception exception) {
exception.printStackTrace();
} finally {
//Closing the socket
try {
socket.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
My server:
public class Main{
private static Socket socket;
public static void main(String[] args) {
try {
int port = 25000;
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("Server Started and listening to the port 25000");
while(true) {
//Reading the message from the client
socket = serverSocket.accept();
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
System.out.println(br.readLine());
}
}
catch (Exception e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch(Exception e){}
}
}
}
To be clear. I can connect to the server. I can send one message from client to console, but no more than one message.
You never read a second line. Your Server accepts a connection, reads one line from that connection and then waits for a new connection, discarding everything that might arrive at the first connection.
Your client however sends all input using the first (and only) connection, which is absolutely correct.
This specific problem can be solved like this:
while(true) {
//Reading the message from the client
socket = serverSocket.accept();
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
while(true){
System.out.println(br.readLine());
}
}
This will cause your program to print everything arriving on that first connection, but it will never accept a second connection.
In order to handle multiple clients, you need a Thread to deal with each one.

Categories