Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 'SyncServer' allowing two users to simultaneously to edit a string variable

Tags:

java

I'm having a bit of trouble finding the cause of my problem.

Functionality of the program is as follows... the Server allows multiple users to log in (connect to the server) and edit the same string variable named text with the starting commands of either rep: (for replace the whole string) or app: (to append to the string).

When the client connects, they have to enter a command. Whatever the command is, it gets echoed back to them in the same window (running the server and client simultaneously in different CMD windows). So if they enter hello, the echo would be ECHO: hello.

If the command entered is rep:tight, the text string variable in the server should change to contain tight and should then be returned back/ displayed back in the client cmd window as tight - without the ECHO.

If the command after that is app:rope, the text string variable in the server should change to contain tightrope and should be returned back/ displayed back in the client cmd window as tightrope.

In addition, the user cannot enter any value under 4 characters and thus SynchClient should display an error message and prompt the user to enter another value.

The issue I'm having is the fact that my echoed values are not changing after every new input. I get the return of the first entered command and that's it and I'm struggling to get my head around it all.

EDIT: Might be best if you ran the program yourself.

Here is what my SynchServer.java file looks like:

import java.io.*;
import java.net.*;
import java.util.*;

public class SynchServer
{

    public static void main(String[] args) throws IOException
    {
        ServerSocket serverSocket = null;
        final int PORT = 1234;
        Socket client;
        ClientHandler handler;

        try
        {
            serverSocket = new ServerSocket(PORT);
        }
        catch (IOException ioEx)
        {
            System.out.println("\nUnable to set up port!");
            System.exit(1);
        }

        System.out.println("\nServer running...\n");

        do
        {
            //Wait for client.
            client = serverSocket.accept();

            System.out.println("\nNew client accepted.\n");
            handler = new ClientHandler(client);
            handler.start();
        }while (true);
    }
}

class ClientHandler extends Thread
{
    private Socket client;
    private Scanner input;
    private PrintWriter output;

    private static String text = "";

    public ClientHandler(Socket socket) throws IOException
    {
        client = socket;

        input = new Scanner(client.getInputStream());
        output = new PrintWriter(client.getOutputStream(),true);
    }

    public void run()
    {
        String head, tail, received;

        received = input.nextLine();
        head = received.substring(0, 4);
        tail = received.substring(4);

        while (!received.equals("QUIT"))
        {
            if (head.equals("rep:"))
                changeText(tail);

            else
                if (head.equals("app:"))
                    appendText(tail);

            output.println(text);
            output.println("ECHO: " + received);
        }

        try
        {
            System.out.println("Closing down connection...");
            client.close();
        }
        catch(IOException ioEx)
        {
            System.out.println("* Disconnection problem! *");
        }
    }

    private synchronized void changeText(String changedText)
    {
        text = changedText;
    }

    private synchronized void appendText(String appendedText)
    {
        text += appendedText;
    }
}

and my SynchClient.java file:

import java.io.*;
import java.net.*;
import java.util.*;

public class SynchClient
{

    public static void main(String[] args) throws IOException
    {
        InetAddress host = null;
        final int PORT = 1234;
        Socket socket;
        Scanner networkInput,keyboard;
        PrintWriter output;

        try
        {
            host = InetAddress.getLocalHost();
        }
        catch(UnknownHostException uhEx)
        {
            System.out.println("\nHost ID not found!\n");
        }

        socket = new Socket(host, PORT);
        networkInput = new Scanner(socket.getInputStream());
        output = new PrintWriter(socket.getOutputStream(),true);

        keyboard = new Scanner(System.in);

        String message, response;

        do
        {   
            System.out.print("\nEnter message ('QUIT' to exit): ");
            message = keyboard.nextLine();

            if (message.length() < 4)
            {
                System.out.print("\nPlease enter a value greater than 4 characters: ");
                message = keyboard.nextLine();
            }

            output.println(message);

            if (!message.equals("QUIT"))
                {
                    response = networkInput.nextLine();
                    System.out.println("\n" + response);
                }
        }while (!message.equals("QUIT"));

        try
        {
            System.out.println("\nClosing down connection...\n");
            socket.close();
        }
        catch(IOException ioEx)
        {
            System.out.println("\n* Disconnection problem! *\n");
        }
    }
}

EDIT 2: My Working Solution:

Server:

public class SynchServer
{

    public static void main(String[] args) throws IOException
    {
        ServerSocket serverSocket = null;
        final int PORT = 1234;
        Socket client;
        ClientHandler handler;

        try
        {
            serverSocket = new ServerSocket(PORT);
        }
        catch (IOException ioEx)
        {
            System.out.println("\nUnable to set up port!");
            System.exit(1);
        }

        System.out.println("\nServer running...\n");

        do
        {
            //Wait for client.
            client = serverSocket.accept();

            System.out.println("\nNew client accepted.\n");
            handler = new ClientHandler(client);
            handler.start();
        }while (true);
    }
}

class ClientHandler extends Thread
{
    private Socket client;
    private Scanner input;
    private PrintWriter output;

    private static String text = "";

    public ClientHandler(Socket socket) throws IOException
    {
        client = socket;

        input = new Scanner(client.getInputStream());
        output = new PrintWriter(client.getOutputStream(),true);
    }

    public void run()
    {
        String head, tail, received;

        received = input.nextLine();

        // create head and tail in case first input is rep: or app:
        head = received.substring(0, 4);
        tail = received.substring(4);

        while (!received.equals("QUIT"))
        {
            if (head.equals("rep:"))
            {
                changeText(tail);
                output.println(text);
                // input for next one
            }
            else
                if (head.equals("app:"))
                {
                    appendText(tail);
                    output.println(text);
                    // get input for next
                }
            else
            {
                //must be some random thing that just needs to be echoed
                output.println(text);
            }

            //Get next input
            received = input.nextLine();
            //and set the head and tail again
            head = received.substring(0, 4);
            tail = received.substring(4);
        }

        try
        {
            System.out.println("Closing down connection...");
            client.close();
        }
        catch(IOException ioEx)
        {
            System.out.println("* Disconnection problem! *");
        }
    }

    private synchronized void changeText(String changedText)
    {
        text = changedText;
    }

    private synchronized void appendText(String appendedText)
    {
        text += appendedText;
    }
}

Client:

public class SynchClient
{

    public static void main(String[] args) throws IOException
    {
        InetAddress host = null;
        final int PORT = 1234;
        Socket socket;
        Scanner networkInput,keyboard;
        PrintWriter output;

        try
        {
            host = InetAddress.getLocalHost();
        }
        catch(UnknownHostException uhEx)
        {
            System.out.println("\nHost ID not found!\n");
        }

        socket = new Socket(host, PORT);
        networkInput = new Scanner(socket.getInputStream());
        output = new PrintWriter(socket.getOutputStream(),true);

        keyboard = new Scanner(System.in);

        String message, response;

        do
        {
            System.out.print("\nEnter message ('QUIT' to exit): ");
            message = keyboard.nextLine();

            while (message.length() < 4)
            {
                System.out.print("\nPlease enter 4 or more characters: ");
                message = keyboard.nextLine();
            }

            output.println(message);
            if (!message.equals("QUIT"))
            {
                response = networkInput.nextLine();

                System.out.println("\n" + response);
            }

        }while (!message.equals("QUIT"));

        try
        {
            System.out.println("\nClosing down connection...\n");
            socket.close();
        }
        catch(IOException ioEx)
        {
            System.out.println("\n* Disconnection problem! *\n");
        }
    }
}
like image 346
Olehi Avatar asked Jan 30 '16 13:01

Olehi


2 Answers

This is not primarily about static fields at all. Your mistake is in this loop:

       while (!received.equals("QUIT")) {
            if (head.equals("rep:"))
                changeText(tail);

            else if (head.equals("app:"))
                appendText(tail);

            output.println(text);
            output.println("ECHO: " + received);
        }

It runs infinitely after first client input and do not read new value from input stream each time.

These lines:

        received = input.nextLine();
        head = received.substring(0, 4);
        tail = received.substring(4);

should be put into the loop:

    while (!received.equals("QUIT")) {
        received = input.nextLine();
        head = received.substring(0, 4);
        tail = received.substring(4);
        ...

UPDATE:

To be precise it has another, secondary problem, these two lines:

            output.println(text);
            output.println("ECHO: " + received);

They should be changed into just:

        output.println("ECHO: " + text);

(otherwise you send two separate lines which is not desired).

like image 164
Andremoniy Avatar answered Oct 30 '22 15:10

Andremoniy


You have a synchronized block that applies to each object separately, not every object, as synchronized block applies to objects not the whole class.

You may use a static lock, so all clients wait for their turn. Check this link to see the comparison between static and not static locks

Static versus non-static lock object in synchronized block

and this

How to lock a method for a whole class using synchronized?


So, you should eliminate static modifier from text field declaration:

private String text = "";

In this case you do not need synchronized for changeText and appendText methods at all.

like image 39
Kostas Chalkias Avatar answered Oct 30 '22 14:10

Kostas Chalkias