2

A few days ago i tried to create a server - client or client Server as an experiment to learn about socket using a thread but then someone told me that i should use swingWorker. I did some research how to use and have implemented it in as practice but it still doesn't work. the swingWorker thread doesn't look like it is running even tho i get a connection and have used .excute(). If you guys can help spot where i am doing wrong that will be great. SwingWorker class is in the startSever() and startClient() method.

    private void startServer() {
        SwingWorker <Void, String> runningServer = new SwingWorker<Void, String>(){
        protected Void doInBackground() {
            try {
                listeningSocket = new ServerSocket(port);
                System.out.println("waiting for connection");
                connection = listeningSocket.accept();
                connected = true;
                System.out.println("Connected");
                String incomeMessage =null;
                while(connected){
                inStream = connection.getInputStream();
                    inDataStream = new DataInputStream(inStream);
                    if (myMessage !=null){
                        outStream = connection.getOutputStream();
                        outDataStream = new DataOutputStream(outStream);
                    outDataStream.writeUTF(myMessage);
                    }

                    if((incomeMessage = inDataStream.readUTF())!=null){
                        clientMessage = incomeMessage;
                        publish(clientMessage);
                        incomeMessage =null;
                    }
                }
            } catch (IOException e) {
                clientMessage = "Connection Lost";
            }
        return null;
    }           
runningServer.execute();
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
user629283
  • 329
  • 1
  • 8
  • 23
  • 1
    This code is very long, so it's a lot of work to analyse. Can you provide an [SSCCE](http://sscce.org/)? – Cyrille Ka Jan 31 '13 at 02:16
  • 1
    sorry i thought it would easier this way if someone wants to copy and paste to test it out. i'll edit now. – user629283 Jan 31 '13 at 02:22
  • Why are you getting a new input stream seemingly repeatedly inside the while loop? – Hovercraft Full Of Eels Jan 31 '13 at 02:24
  • Your edit is not an [sscce](http://sscce). Consider reading the link before your next edit. – Hovercraft Full Of Eels Jan 31 '13 at 02:25
  • is that better? the client side is pretty similar it just has connection = new Socket(remoteMachine,port); – user629283 Jan 31 '13 at 02:25
  • 2
    I think the problem is you are trying to read/write within the same thread. This means that while you are waiting for something to be written, the thread is blocking, meaning nothing can be sent – MadProgrammer Jan 31 '13 at 02:27
  • For [reference](http://stackoverflow.com/a/3245805/230513). – trashgod Jan 31 '13 at 02:33
  • that for the link about SSCCE ckarmann and hovercraft i'll keep that in mind next time i post for help. hovercraft - i'll try moving that and see if that works. MadProgrammer - i'll try splitting the thread up once i have moved the input stream. cheers for the link trashgod. but i'll try and look through what hovercraft and madprogrammer first then i'll check the link. it looks like someone has done it. – user629283 Jan 31 '13 at 02:46

3 Answers3

6

Here's a VERY basic example.

Basically, because you program requires asynchronous communications (that is, you need to be able to read from the socket AND write to it at the same time), you need to offload each stream to a separate thread.

The management process of this example is, well, no existent. Realistically, you should have some kind of "connection" manager that would be able to cleanly close the output and input threads so that, for example, when the user types "bye", the output thread would be able to tell the connection manager that the connection should be terminated. It would then tell the input thread to stop reading any new message and terminate...

Client

public class Client {

    public static void main(String[] args) {

        try {
            Socket master = new Socket("localhost", 8900);
            new Thread(new InputHandler(master)).start();
            new Thread(new OuputHandler(master)).start();
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    public static class InputHandler implements Runnable {

        private Socket socket;

        public InputHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            boolean commune = true;
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while (commune) {
                    String text = reader.readLine();
                    System.out.println("\n<server> " + text);
                    if (text.toLowerCase().equals("bye")) {
                        commune = false;
                    }
                }
            } catch (Exception exp) {
                exp.printStackTrace();
            } finally {
                try {
                    reader.close();
                } catch (Exception e) {
                }
                try {
                    socket.close();
                } catch (Exception e) {
                }
            }
        }
    }

    public static class OuputHandler implements Runnable {

        private Socket socket;

        public OuputHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            boolean commune = true;
            BufferedWriter writer = null;
            try {
                writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                Scanner scanner = new Scanner(System.in);
                while (commune) {
                    System.out.print("> ");
                    String text = scanner.nextLine();
                    writer.write(text);
                    writer.newLine();
                    writer.flush();
                    if (text.equalsIgnoreCase("bye")) {
                        commune = false;
                    }
                }
            } catch (Exception exp) {
                exp.printStackTrace();
            } finally {
                try {
                    writer.close();
                } catch (Exception e) {
                }
                try {
                    socket.close();
                } catch (Exception e) {
                }
            }
        }
    }
}

Server

public class Server {

    public static void main(String[] args) {

        try {
            ServerSocket master = new ServerSocket(8900);
            Socket socket = master.accept();
            new Thread(new InputHandler(socket)).start();
            new Thread(new OuputHandler(socket)).start();
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    public static class InputHandler implements Runnable {

        private Socket socket;

        public InputHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            boolean commune = true;
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while (commune) {
                    String text = reader.readLine();
                    System.out.println("\n<client> " + text);
                    if (text.toLowerCase().equals("bye")) {
                        commune = false;
                    }
                }
            } catch (Exception exp) {
                exp.printStackTrace();
            } finally {
                try {
                    reader.close();
                } catch (Exception e) {
                }
                try {
                    socket.close();
                } catch (Exception e) {
                }
            }
        }
    }
    public static class OuputHandler implements Runnable {

        private Socket socket;

        public OuputHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            boolean commune = true;
            BufferedWriter writer = null;
            try {
                writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                Scanner scanner = new Scanner(System.in);
                while (commune) {
                    System.out.print("> ");
                    String text = scanner.next();
                    writer.write(text);
                    writer.newLine();
                    writer.flush();
                    if (text.equalsIgnoreCase("bye")) {
                        commune = false;
                    }
                }
            } catch (Exception exp) {
                exp.printStackTrace();
            } finally {
                try {
                    writer.close();
                } catch (Exception e) {
                }
                try {
                    socket.close();
                } catch (Exception e) {
                }
            }
        }
    }
}

Update (whine)

While I have your source code in front of me...

There should very, very, rarely be a need to do textMessage.addKeyListener(this)

Because you are using a JTextField, you should be using a ActionListener instead. There are a a number of important reasons for this, but for you, the main one would be the fact that a "accept" action is Look and Feel dependent. While most systems do use Enter as there "accept" action, is not a guarantee.

Have a look at How to Write a Action Listener for more information

Given the general complexity of what you are trying to do, +1 for a overall good attempt!

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • could you explain why i would use printWrite rather then writeUTF? thank you – user629283 Jan 31 '13 at 02:59
  • That comes down to your needs. Are you expecting to need to UTF encoded text? If so, then you should provide support for it (making sure you read the UTF text out on the other end) - Basically, `read/writeUTF` allows you to support different character encodings other then the basic ASCII character set. – MadProgrammer Jan 31 '13 at 03:02
  • thanks a lot for the help guys i'll continue the project tomorrow when i get home. it is 3am right now so i better sleep and yet again thank you very much – user629283 Jan 31 '13 at 03:07
  • hey madProgrammer + trashgod i did some research about buffer reader and buffer writer vs datainputStream. i just found out that datainputstream is note safe in multi-threading so i'll use bufferreader and that from now on here is my reference [http://docs.oracle.com/javase/7/docs/api/java/io/DataInputStream.html]. and again thanks for the help – user629283 Jan 31 '13 at 20:40
  • @user62927 Remember that when people talk about thread safe, they mean that the class can/can't be accessed by multiple threads. Seen as you're only using a single thread to perform atomic operations (either read or write) and on a single thread, you should be okay. If you had multiple threads trying to read/write from/to the same same stream, then you'd have concerns - IMHO – MadProgrammer Jan 31 '13 at 20:55
  • @MadProgrammer i got the server Listening now thanks to your code which helped me test the server and client listening to each other. ive found my problem out to be the send and i am sorry i cant help but use keyListener (wanted to make it look a bit fancy as i practice) – user629283 Feb 05 '13 at 01:52
5

Using this example, the following changes work with a single telnet client.

private PrintWriter out;
...
public void keyPressed(KeyEvent e) {
    if (e.getKeyChar() == KeyEvent.VK_ENTER) {
        myMessage = friendLabel + textMessage.getText();
    if (out != null) {
        out.println(myMessage);
    }
    ...
}
...
protected Void doInBackground() {
    try {
        listeningSocket = new ServerSocket(port);
        System.out.println("Waiting for connection");
        connection = listeningSocket.accept();
        connected = true;
        System.out.println("Connected");
        Scanner in = new Scanner(connection.getInputStream());
        out = new PrintWriter(connection.getOutputStream(), true);
        publish("Connected");
        while (true) {
            publish(in.nextLine());
        }
    } catch (IOException e) {
        clientMessage = "Connection Lost";
        try {
            connection.close();
            System.out.println("Closed");
        } catch (IOException e1) {
            e1.printStackTrace();
            connected = false;
        }
    }
    return null;
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
-1

I see your server port is 8900 and your client port is 8900 too. I am not sure if it matters if the server and client are running on the same machine...

Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
bleedcloud
  • 21
  • 2
  • In order for a `Socket` to communicate with the a `ServerSocket` they must be on the same port. That's how it works – MadProgrammer Jan 31 '13 at 02:43
  • If u run the server code and client code on the same mathine, and u are code are all point the port 8900, there will be a crash! so run them on different machine and try again... Or, change the port one of them and point out the client port in serverscoket,point out the server port in clientSocket... this is just for the two run on the – bleedcloud Jan 31 '13 at 02:50
  • 2
    No, there won't be. It works fine - If you open two `ServerSockets` on the same port, then it will complain, but the OP isn't doing that - I ran the code, it works fine (except for the problem they are having of course) – MadProgrammer Jan 31 '13 at 02:51
  • Yeah i read that online too that is why i kept the port the same. – user629283 Jan 31 '13 at 02:54