Java erlang socket communication - java

i'm having trouble with the socket reading and writing through threads. The server's in erlang and the client in Java. The way i'm doing it is this:
PrintWriter printer = new PrintWriter(socket.getOutputStream(), true);
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
TransmitterTwo trans = new TransmitterTwo(socket);
trans.start(); // Gets the message from socket
TransmitterTwo Class:
public class TransmitterTwo extends Thread {
Socket socket;
String message;
TransmitterTwo(Socket socket) {
this.socket = socket;
}
public String getMessageFromSocket() {
return message;
}
public void run() {
try {
String response = null;
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while ((response = reader.readLine()) != null) {
System.out.println("Server response: "+ response);
this.message = response;
}
socket.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
The Problem is in the main client class. The idea is to: receive input from the console, send it to the socket, the server handles the logic and sends a response through the socket. Then on this client I check the response and do whatever i need to do. It's a registration flow, i register, i receive "register_ok", then i login...etc etc. The part of the loop where i'm having trouble is this:
while(true) {
String readerInput = reader.readLine(); // Read from console
printer.println(readerInput.trim()); // Sends it to the socket
while(trans.message == null);
socketMessage = trans.message;
Is this the right approach? The problem is that 'socketmessage' prints the previous received message, it's like..1 step behind, obviously this is thread related but I can't figure out the problem....help? Thanks

Your current approach is suboptimal because you're wasting your main thread spinning waiting on that variable to be updated. Because of how memory visibility works in java it may appear to never be updated (even if it actually is), or you may get stale values when you do access that variable. A more robust approach would be to pass messages between the threads using some of the built in collections in java:
public static void main(String[] args) {
// This queue will be the link between the threads where
// they can pass messages to each other
BlockingQueue<String> messages = new LinkedBlockingQueue<>();
PrintWriter printer = new PrintWriter(socket.getOutputStream(), true);
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
TransmitterTwo trans = new TransmitterTwo(socket, queue);
trans.start(); // Gets the message from socket
...
while(true) {
String readerInput = reader.readLine(); // Read from console
printer.println(readerInput.trim()); // Sends it to the socket
// Wait for the other thread to push a message in to the queue.
String recv = messages.take();
}
}
public class TransmitterTwo extends Thread {
final Socket socket;
final BlockingQueue<String> queue;
TransmitterTwo(Socket socket, BlockingQueue<String> queue) {
this.socket = socket;
this.queue = queue;
}
public void run() {
try {
String response = null;
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while ((response = reader.readLine()) != null) {
System.out.println("Server response: " + response);
// Add the response from the server to the queue
queue.add(response);
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
This approach will never get stale values, and the take() operation on the main thread will block until there is some response from the server.

Related

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.

How to give an automated response back when receiving a specific message from the client (Java, sockets)

I basically was trying to give a response back from my server if my client sends me the message "Hello mr server". However it doesn't.
Here is my code :
public class Server {
public static final int PORT = 6666;
public static void main(String[] args) throws IOException {
new Server().runServer();
}
public void runServer() throws IOException {
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println("Server up and ready for connections.....");
while (true) {
Socket socket = serverSocket.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //for fetching data
String str = br.readLine(); //for fetching data
System.out.println("Client Data:" + str + '\n');
String dataSendingToClient = "gg";
OutputStreamWriter os = new OutputStreamWriter(socket.getOutputStream()); //for sending data
PrintWriter out = new PrintWriter(os); //for sending data
out.println(dataSendingToClient);
os.flush();
if (br.equals("hey mr server")){
OutputStreamWriter os2 = new OutputStreamWriter(socket.getOutputStream()); //for sending data
PrintWriter out2 = new PrintWriter(os); //for sending data
out2.println("hey mr client");
os.flush();
}
}
}
}
You are using br.equals("hey mr server") which will always return false, since br is not a String, but a BufferedReader
Instead you should use your already defined str variable str.equals("hey mr server")
Also note that with your current code, your server will only read one message from the client before moving on to the next connection
If you want your server to read more messages from a single client, you will need to loop until the client sends a disconnect message/the socket closes
while(true)
{
Socket socket = serverSocket.accept();
BufferedReader br = [...];
PrintWriter out = [...];
for(String message = br.readLine(); message != null; message = br.readLine())
{
//do stuff
//message is each line from the client
}
}
If you have multiple clients trying to connect, you will need to multithread the connections
I would recommend a class to enclose the connection details and use Stacks to poll if the client sent data
public static void main(String[] args) //or whatever other method you're running in
{
List<Connection> clients = new ArrayList<Connection>(); //some data structure to hold the clients
//start accepting connections
new Thread(new Runnable()
{
public void run()
{
while(true)
Connection client = new Connection(serverSocket.accept());
}
}).start();
//do something with the clients, read/write/whatever
}
private class Connection extends Runnable
{
private BufferedReader reader;
private PrintWriter writer;
private Queue<String> messages;
public Connection(Socket s)
{
reader = [...];
writer = [...];
messages = new LinkedList<String>();
}
public void run()
{
//just keep reading
while(true)
messages.add(reader.readLine();
}
public String read()
{
messages.poll();
}
public void write(String msg)
{
writer.write(msg);
writer.flush();
}
}
Note: take that as rough pseudocode

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.

Java Socket Communication "deadlock"

Hi I am trying to implement server operating with multiply clients
The problem is that the server does not receive the message from inputstream and wait until it happen. if the client don't close the stream after writing to it the server will continue to wait. After the client send the message, he try to read from the inputstream waiting for response, but the server is waiting for the request. So.. deadlock
This is my client class
public class Client implements Runnable{
...
#Override
public void run() {
BufferedReader is = null;
BufferedWriter os = null;
try(Socket socket = new Socket(address.getHostName(), address.getPort());){
String request = String.format("%s-%d-%s",this.destination, this.desiredPlace, this.paymentMethod.toString());
os = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter pw = new PrintWriter(os, true);
pw.write(request);
pw.flush();
// if I close the stream here the request will be send, but this will close the socket so the I will not receive response.
String response;
while ((response = is.readLine()) != null){
System.out.println(response);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
And this is my server class
public void perform() throws IOException, DestionationProcessingException, InterruptedException {
try (ServerSocket server = new ServerSocket(port);) {
StandalonePayDesk offLinePayDesk = new StandalonePayDesk(ticketManager);
this.threadPool.submit(offLinePayDesk);
while (true) {
Socket socket = server.accept();
RequestHandler handler = new RequestHandler(this.threadPool, offLinePayDesk, this.ticketManager);
handler.process(socket);
}
}
}
and RequestHandler class for processing each client
try (BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter writer = new PrintWriter(client.getOutputStream(), true)) {
writer.println("hello");
writer.flush();
String line;
while ((line = reader.readLine()) != null) {
String[] lineTokens = line.split("-");
...
Can anyone help me to solve this problem ?
pw.write(request);
Your client is writing a request but not a line. Your server is reading a line, with readLine(), and will block until the line terminator arrives, which is never, so it will never send a reply, so your client will never receive it, so it will block forever.
Change the above to:
pw.println(request);

ServerSocket accept continues to block

I'm having some trouble simulating a connection to my Server Socket, accept seems to continue blocking as it doesn't "see" the connection.
Here's some simplified code
#Test
public void testPDMServerThread() {
try {
ServerSocket serverSocket = new ServerSocket(0);
int port = serverSocket.getPort();
Socket clientSocket = new Socket("localhost", port);
PrintWriter clientRequest = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader serverResponse = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
serverThread = new ProducerMonitorServerThread(serverSocket.accept());
clientRequest.write("Hi!");
serverThread.start();
System.out.println("Server says: " + serverResponse.readLine());
assertEquals("RUNNABLE", serverThread.getState().toString());
} catch (IOException e) {
}
}
And here's the thread where the server should respond
public class ProducerMonitorServerThread extends Thread {
private Socket socket;
public ProducerMonitorServerThread(Socket socket) {
super("PDM");
this.socket = socket;
}
#Override
public void run() {
try {
PrintWriter serverResponse = new PrintWriter(socket.getOutputStream(), true);
BufferedReader clientRequest = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String serverInput, clientOutput;
while((serverInput = clientRequest.readLine()) != null) {
clientOutput = "Bye!";
System.out.println("Client says: " +serverInput);
serverResponse.write(clientOutput);
}
serverResponse.close();
clientRequest.close();
socket.close();
} catch (IOException e) {
}
}
}
It never seems to get past this line which is why I think accept is not seeing the connection
serverThread = new ProducerMonitorServerThread(testServer.accept());
I'm sure there's something fundamental that I'm just not seeing.
First of all, you should not ignore exceptions like you're doing.
The problem is not with accept. The problem is that the server uses readLine(), and the client never sends any EOL character, and never closes the socket. So the server is blocked waiting for an EOL to appear in the reader. The same is true for the client: it uses readLine() and the server never sends any EOL.
Use a debugger. It will help you find the cause of such problems.

Categories