Приложение Knock Knock с сервером и пользовательским интерфейсом

Я создаю простое приложение Knock Knock (программирование сокетов), где есть сервер localhost и клиент. Программа проста, сервер будет рассказывать шутки тук-тук, вот как это должно быть,

Server: Knock Knock
Client: Who's there?
Server: Turnip.
Client: Turnip Who?
Server: Turnip the heat.

Так вот как должна была проходить программа. но дело в том, что мой графический интерфейс не показывает никаких сообщений. в моей текстовой области. Вот мои коды.

Сервер:

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

public class KnockKnockServer {
    public static void main(String[] args) throws IOException {

        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(4444);
        } catch (IOException e) {
            System.err.println("Could not listen on port: 4444.");
            System.exit(1);
        }

        Socket clientSocket = null;
        try {
            clientSocket = serverSocket.accept();
        } catch (IOException e) {
            System.err.println("Accept failed.");
            System.exit(1);
        }

        PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
        BufferedReader in = new BufferedReader(
                new InputStreamReader(
                clientSocket.getInputStream()));
        String inputLine, outputLine;
        KnockKnockProtocol kkp = new KnockKnockProtocol();

        outputLine = kkp.processInput(null);
        out.println(outputLine);

        while ((inputLine = in.readLine()) != null) {
             outputLine = kkp.processInput(inputLine);
             out.println(outputLine);
             if (outputLine.equals("Bye."))
                break;
        }
        out.close();
        in.close();
        clientSocket.close();
        serverSocket.close();
    }
}

Протокол «тук-тук»

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

public class KnockKnockProtocol {
    private static final int WAITING = 0;
    private static final int SENTKNOCKKNOCK = 1;
    private static final int SENTCLUE = 2;
    private static final int ANOTHER = 3;

    private static final int NUMJOKES = 5;

    private int state = WAITING;
    private int currentJoke = 0;

    private String[] clues = { "Turnip", "Little Old Lady", "Atch", "Who", "Who" };
    private String[] answers = { "Turnip the heat, it's cold in here!",
                                 "I didn't know you could yodel!",
                                 "Bless you!",
                                 "Is there an owl in here?",
                                 "Is there an echo in here?" };

    public String processInput(String theInput) {
        String theOutput = null;

        if (state == WAITING) {
            theOutput = "Knock! Knock!";
            state = SENTKNOCKKNOCK;
        } else if (state == SENTKNOCKKNOCK) {
            if (theInput.equalsIgnoreCase("Who's there?")) {
                theOutput = clues[currentJoke];
                state = SENTCLUE;
            } else {
                theOutput = "You're supposed to say \"Who's there?\"! " +
                "Try again. Knock! Knock!";
            }
        } else if (state == SENTCLUE) {
            if (theInput.equalsIgnoreCase(clues[currentJoke] + " who?")) {
                theOutput = answers[currentJoke] + " Want another? (y/n)";
                state = ANOTHER;
            } else {
                theOutput = "You're supposed to say \"" + 
                clues[currentJoke] + 
                " who?\"" + 
                "! Try again. Knock! Knock!";
                state = SENTKNOCKKNOCK;
            }
        } else if (state == ANOTHER) {
            if (theInput.equalsIgnoreCase("y")) {
                theOutput = "Knock! Knock!";
                if (currentJoke == (NUMJOKES - 1))
                    currentJoke = 0;
                else
                    currentJoke++;
                state = SENTKNOCKKNOCK;
            } else {
                theOutput = "Bye.";
                state = WAITING;
            }
        }
        return theOutput;
    }
}

Клиент.

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


public class KnockKnockClient {

    public String fromServer;
    public String fromUser;

    public void Client() throws IOException {

        Socket kkSocket = null;
        PrintWriter out = null;
        BufferedReader in = null;


        try {
            kkSocket = new Socket("127.0.0.1", 4444);
            out = new PrintWriter(kkSocket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(kkSocket.getInputStream()));
        } catch (UnknownHostException e) {
            System.err.println("Don't know about host: 127.0.0.1");
            System.exit(1);
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for the connection to: 127.0.0.1");
            System.exit(1);
        }

        BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));

        while ((fromServer = in.readLine()) != null) {
            System.out.println("Server: " + fromServer);

            if (fromServer.equals("Bye."))
                break;

            fromUser = stdIn.readLine();
        if (fromUser != null) {
                System.out.println("Client: " + fromUser);
                out.println(fromUser);
        }
        }

        out.close();
        in.close();
        stdIn.close();
        kkSocket.close();
    }


}

И пользовательский интерфейс

 import java.awt.event.ActionListener;



    public class KnockKnockWindow extends JFrame {

        JTextArea clientTextArea;
        JTextArea serverTextArea;
        JButton submitButton;


        public KnockKnockWindow() {

            super("Chat Window");
            setVisible(true);
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setLocationRelativeTo(null);
            setSize(420,228);

            getContentPane().setLayout(null);

            clientTextArea = new JTextArea();
            clientTextArea.setBounds(10, 118, 278, 51);
            getContentPane().add(clientTextArea);


            serverTextArea = new JTextArea();
            serverTextArea.setBounds(10, 11, 278, 96);
            getContentPane().add(serverTextArea);

            submitButton = new JButton("Submit");
            submitButton.setBounds(298, 118, 89, 51);
            getContentPane().add(submitButton);
        }


        public void setServerText(String fromServer){
            serverTextArea.setText(fromServer);
        }

        public void setClientText(String fromClient){
            clientTextArea.setText(fromClient);
        }

        public String returnClientText(){
            return clientTextArea.getText();
        }

        public void addSubmitListener(ActionListener sub){
            submitButton.addActionListener(sub);
        }

    }   



The Controller


import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


public class KnockKnockController {

    private KnockKnockClient client;
    private KnockKnockWindow window;

    public KnockKnockController(KnockKnockClient client, KnockKnockWindow window){
        this.client = client;
        this.window = window;

        window.addSubmitListener(new SubmitListener());
        window.setServerText(client.fromServer);
    }

    public class SubmitListener implements ActionListener{

        public void actionPerformed(ActionEvent arg0) {
            client.fromUser = window.returnClientText();
        }
    }
}

И основное приложение

import javax.swing.JFrame;

public class KnockTest extends JFrame{

    public static void main (String[] args){
        KnockKnockClient kkcl = new KnockKnockClient();
        KnockKnockWindow kkw = new KnockKnockWindow();
        KnockKnockController kkc = new KnockKnockController(kkcl,kkw);
    }
}

Сначала запустим сервер, потом основной.

Но почему я не получаю никаких сообщений от сервера? когда я нажимаю старт. В текстовой области сервера должно быть написано KnockKnock. но, похоже, он не показывает, есть идеи? извините за длинный код сообщения, но я не знаю, чтобы сократить их здесь. так как я знаю, что большинство из них важны


person user962206    schedule 11.02.2012    source источник
comment
Я бы порекомендовал отладчик с (несколько низким) чувством юмора.   -  person Perception    schedule 11.02.2012
comment
я предполагаю, что отрицательные голоса связаны с тем, что вы разместили много кода, а затем все, почему это не сработает. (кстати, я не голосовал) Такие люди, как вы, сузили проблему.   -  person Lyndon White    schedule 11.02.2012
comment
+1 хотя, вопрос сделал какой-то ТУК-ТУК в моей голове :-)   -  person nIcE cOw    schedule 11.02.2012


Ответы (1)


Где именно вы печатаете в текстовую область, как вы говорите, цикл while просто получает текст и печатает его на консоли.

// Put this code somewhere in the Client class so that when it receives something,
// it can be added to the `JTextArea`
while ((fromServer = in.readLine()) != null) 
{
    // You seems like missed the part that sends it to the textArea
    System.out.println("Server: " + fromServer);
    // Here send the received thing to your textarea, which goes something like this
    String str = "Server : " + fromServer + "\n";
    tarea.append(str);

    if (fromServer.equals("Bye."))
        break;

    // You can remove this part and put it inside the textField's actionPerformed method. 
    fromUser = stdIn.readLine();
    if (fromUser != null) 
    {
        System.out.println("Client: " + fromUser);
        out.println(fromUser);
    }
}

СОВЕРШЕННО НОВАЯ РЕДАКЦИЯ:

Просто запустите свой KnockKnockServer из командной строки, а не из вашего класса, расширяющего JFrame. Просто напишите java KnockKnockServer, чтобы запустить ваш сервер в командной строке, теперь в новой командной строке скомпилируйте этот класс, который я вам даю, и запустите его также, как java KnockKnockClient, вы поймете, что он не работает полностью.

import java.awt.BorderLayout;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;


public class KnockKnockClient extends JFrame
{

    public String fromServer;
    public String fromUser;
    // Added by me.--------------------
    private JTextArea tarea;
    private JTextField tfield;
    private JScrollPane spane;
    private PrintWriter out = null;
    /*------------------------------------*/

    public void Client() throws IOException 
    {
        Socket kkSocket = null;
        //PrintWriter out = null;  Shifted this to the instance variable
        BufferedReader in = null;

        BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
        try {
            kkSocket = new Socket("127.0.0.1", 4444);
            out = new PrintWriter(kkSocket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(kkSocket.getInputStream()));
        } catch (UnknownHostException e) {
            System.err.println("Don't know about host: 127.0.0.1");
            System.exit(1);
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for the connection to: 127.0.0.1");
            System.exit(1);
        }

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        JPanel contentPane = new JPanel();

        tarea = new JTextArea(10, 10);
        spane = new JScrollPane(tarea);
        tarea.setLineWrap(true);
        tfield = new JTextField(10);

        tfield.requestFocusInWindow();

        contentPane.setLayout(new BorderLayout());
        contentPane.add(spane, BorderLayout.CENTER);
        contentPane.add(tfield, BorderLayout.PAGE_END);

        setContentPane(contentPane);
        pack();
        setVisible(true); 

        Thread receiveMessage = new Thread(new ReceiveChat(in, stdIn, out));    
        receiveMessage.start();



        tfield.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent ae)
            {
                // Here you will send it to the server side too, put that code here
                fromUser = tfield.getText() + "\n";
                if (fromUser != null) 
                {
                    System.out.println("Client: " + fromUser);
                    tarea.append(fromUser);
                    out.println(fromUser);
                    tfield.setText("");
                }
            }
        });
        //out.close();
        //in.close();
        //stdIn.close();
        //kkSocket.close();
     }    

     private class ReceiveChat implements Runnable
     {
        private BufferedReader in;
        private BufferedReader stdIn;
        private PrintWriter out;

        public ReceiveChat(BufferedReader in, BufferedReader stdIn, PrintWriter out)
        {
            this.in = in;
            this.stdIn = stdIn;
            this.out = out;
        }

        public void run()
        {
            try
            {
                while ((fromServer = in.readLine()) != null) {
                //System.out.println("Server: " + fromServer);
                String str = "Server : " + fromServer + "\n";
                tarea.append(str);
                tarea.setCaretPosition(tarea.getDocument().getLength());

                if (fromServer.equals("Bye."))
                    break;
                /*Commented out by me.*/
                /*fromUser = stdIn.readLine();
                if (fromUser != null) {
                    System.out.println("Client: " + fromUser);
                    out.println(fromUser);
                }   */
                }
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
     }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                KnockKnockClient client = new KnockKnockClient();
                try
                {
                    client.Client();
                }
                catch(Exception e)
                {
                    e.printStackTrace();
                }
            }
        });
    }
}

Просто позвольте циклу while вашего класса KnockKnockServer выглядеть так:

while ((inputLine = in.readLine()) != null) 
{
    if (inputLine.length() > 0)
    {
        outputLine = kkp.processInput(inputLine);            
        out.println(outputLine);
        if (outputLine.equals("Bye."))
            break;
    }   
}

Это заставит его работать так, как ожидалось.

person nIcE cOw    schedule 11.02.2012
comment
так как бы я показал в текстовом поле? и из текстовой области клиента. как бы я поместил это в stdIn.readLine();? - person user962206; 11.02.2012
comment
@user962206 user962206: проверьте это последнее редактирование, возможно, это поможет вам в этом направлении. - person nIcE cOw; 11.02.2012
comment
Кстати, как насчет PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); BufferedReader in = new BufferedReader( new InputStreamReader( clientSocket.getInputStream())); Строка inputLine, outputLine; KnockKnockProtocol kkp = new KnockKnockProtocol(); outputLine = kkp.processInput(null); out.println (выходная строка); как насчет той части? я все равно добавлю его в свой класс Client? - person user962206; 11.02.2012
comment
@user962206 user962206: я только что понял, что вам нужно использовать Swing Worker для этого, так как ваш цикл while заблокирует всю часть GUI в этом. Было бы намного мудрее, если бы вы сделали свой клиентский класс также классом графического интерфейса, вам будет намного проще справляться с такими вещами. Включая рабочего Swing или поток для вашего цикла while. - person nIcE cOw; 11.02.2012
comment
как я могу отправить его на сервер? - person user962206; 11.02.2012
comment
Посмотрите, проверьте это последнее редактирование, которое я даю, но не используйте Thread, как я, используйте SwingWorker, просто запустите свой KnockKnockServer из командной строки и запустите этот класс KnockKnockClient, который я даю вам, в другом CommandPrompt, вы получите представление как это сделать. Хотя это не работает в хорошем смысле. - person nIcE cOw; 11.02.2012
comment
@ user962206: Без SwingWorker ваш графический интерфейс зависнет. Затем используйте только командную строку, не используйте графический интерфейс, пока вам не будет разрешено использовать потоки. Swing не является потокобезопасным. - person nIcE cOw; 11.02.2012
comment
Хорошо, это странно. наш профессор еще не обсуждал Threading, но он ожидает, что у нас будет это в приложении Knock Knock с графическим интерфейсом. это может быть вина нашего инструктора, я думаю? Я уже пробовал. это уже работает, хотя каждый раз, когда я нажимаю ввод, он продолжает говорить, что вы должны сказать это - person user962206; 11.02.2012
comment
@ user962206: Да, правда, похоже, что-то происходит в KnockKnockProtocol, еще не проверял, думал, что вы можете сделать эту часть самостоятельно. - person nIcE cOw; 11.02.2012
comment
@user962206 user962206: Просто поместите туда то, что когда-либо находилось в вашем цикле while KnockKnockServer, если (inputLine.length() › 0){yourCodeAlreadyWritten}, вот и все. Работает потом. - person nIcE cOw; 11.02.2012
comment
@user962206 user962206: Вот еще раз посмотрите это редактирование, куда его поместить, чтобы оно работало. - person nIcE cOw; 12.02.2012