简体   繁体   English

Java Instant Messenger-将多个客户端连接到服务器和另一个

[英]Java Instant Messenger - Connecting multiple clients to server and oneanother

I have written a simple client/server instant messaging program, which has basic functionality. 我编写了一个简单的客户端/服务器即时消息传递程序,该程序具有基本功能。

As it currently stands, I can send/receive messages between the server and one connected client. 就目前而言,我可以在服务器和一个连接的客户端之间发送/接收消息。 However, subsequent clients will not connect to the server. 但是,后续的客户端将无法连接到服务器。

I wish to implement features which allow for the following: 我希望实现允许以下功能:

Successful connection of 2+ clients to the server; 成功将2个以上的客户端连接到服务器;

Multiple clients connecting to the Server and successfully communicating with each other and server. 多个客户端连接到服务器并成功与彼此和服务器通信。

I think I need to setup a new thread for each connection, but I'm unsure how to go about this. 我想我需要为每个连接设置一个新线程,但是我不确定该怎么做。

Please advise (see my code below). 请提出建议(请参阅下面的我的代码)。

Any help is greatly appreciated. 任何帮助是极大的赞赏。

Many thanks. 非常感谢。

Client.java: Client.java:

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Date; //timestamp functionality

import javax.swing.*;

public class Client extends JFrame { //inherits from JFrame

    //1. Creating instance variables

    private JTextField userText; //where user inputs text
    private JTextArea chatWindow; //where messages are displayed
    private String fullTimeStamp = new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date());
    //fullTimeStamp - MM = months; mm = minutes; HH = 24-hour cloc
    private ObjectOutputStream output; //output from Client to Server
    private ObjectInputStream input; //messages received from Server
    private String message ="";
    private String serverIP;
    private Socket connection;

    //2. Constructor (GUI)
    public Client(String host){ //host=IP address of server
        super("Mick's Instant Messenger [CLIENT]");
        serverIP = host; //placed here to allow access to private String ServerIP
        userText = new JTextField();
        userText.setEditable(false);
        userText.addActionListener(
            new ActionListener(){
                public void actionPerformed(ActionEvent event){
                    sendMessage(event.getActionCommand()); //For this to work, must build sendData Method
                    userText.setText(""); //resets userText back to blank, after message has been sent to allow new message(s)
                }
            }

                );
        add(userText, BorderLayout.SOUTH);
        chatWindow = new JTextArea();
        add(new JScrollPane(chatWindow), BorderLayout.CENTER); //allows you to scroll up and down when text outgrows chatWindow
        chatWindow.setLineWrap(true); //wraps lines when they outgrow the panel width
        chatWindow.setWrapStyleWord(true); //ensures that above line wrap occurs at word end
        setSize(400,320);
        this.setLocationRelativeTo(null); //places frame in center of screen
        setVisible(true);
    }

    //3. startRunning method
    public void startRunning(){
        try{
            connectToServer(); //unlike Server, no need to wait for connections. This connects to one specific Server.
            setupStreams();
            whileChatting();
        }catch(EOFException eofException){


            //Display timestamp for disconnection
            showMessage("\n\n" + fullTimeStamp);
            showMessage("\nConnection terminated by CLIENT! ");


        }catch(IOException ioException){
            ioException.printStackTrace();
        }finally{
                closeCrap();
            }

    }

    //4. Connect to Server
    void connectToServer() throws IOException{
        showMessage(" \n Attempting connection to SERVER... \n");
        connection = new Socket(InetAddress.getByName(serverIP), 6789);//Server IP can be added later
        showMessage(" Connected to: " +connection.getInetAddress().getHostName() ); //displays IP Address of Server
    }

    //5. Setup streams to send and receive messages
    private void setupStreams() throws IOException{ 
        output = new ObjectOutputStream(connection.getOutputStream());
        output.flush();
        input = new ObjectInputStream(connection.getInputStream());
        showMessage("\n Streams are now setup! \n");

    }

    //6. While chatting method
    private void whileChatting() throws IOException{


        //Display timestamp for connection
        showMessage("\n" + fullTimeStamp);

        ableToType(true);
        String timeStamp = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date());//timestamp
        do{
            try{
                message = (String) input.readObject(); //read input, treat as String, store in message variable
                showMessage("\n" + message);
            }catch(ClassNotFoundException classNotfoundException){
                showMessage("\n I don't know that object type");
            }

        //***broken by timestamp?***    
        }while(!message.equalsIgnoreCase("SERVER " + "[" + timeStamp  + "]" + ": " + "END")); //Conversation happens until Server inputs 'End'

    }

    //7. Close the streams and sockets
    private void closeCrap(){
        showMessage("\n\nClosing streams and sockets...");
        ableToType(false);//disable typing feature when closing streams and sockets
        try{
            output.close();
            input.close();
            connection.close();
        }catch(IOException ioException){
            ioException.printStackTrace(); //show error messages or exceptions
        }
    }

    //8. Send Messages to Server
    private void sendMessage(String message){
        try{
        String timeStamp = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date());//timestamp
        output.writeObject("CLIENT" + " [" + timeStamp + "]" + ": " + message);
        output.flush();
        showMessage("\nCLIENT" + " [" + timeStamp + "]" + ": " + message);
    }catch(IOException ioexception){
        chatWindow.append("\n Error: Message not sent!");
    }

    }

    //9.change/update chatWindow
    private void showMessage(final String m){
        SwingUtilities.invokeLater(
                new Runnable(){
                    public void run(){
                        chatWindow.setEditable(false); //disallows text editing in chatWindow
                        chatWindow.append(m); //appends text, which was passed in from above
                    }
                }

                );
    }

    //10. Lets user type
            private void ableToType(final boolean tof){
                SwingUtilities.invokeLater(
                        new Runnable(){
                            public void run(){
                                userText.setEditable(tof); //passes in 'true'
}
        }

                        );
            }
}

Server.Java: Server.Java:

import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

import java.util.Date;//timestamp functionality


public class Server extends JFrame{ //inherits from JFrame

    //1. Instance Variables

    private JTextField userText; //where messages are typed
    private JTextArea chatWindow; //where messages are displayed
    private String fullTimeStamp = new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date());
    //fullTimeStamp - MM = months; mm = minutes; HH = 24-hour clock

    //setting up the streams
    private ObjectOutputStream output; //messages being sent by user
    private ObjectInputStream input; //messages being received by user;

    private ServerSocket server;

    private Socket connection; //Socket = sets up connection between one computer and another.

    //2. Constructor (GUI)
    public Server(){
    super("Mick's Instant Messenger [SERVER]"); //window title
    userText = new JTextField();
    userText.setEditable(false); //you cannot type anything, unless you are connected to someone else
    userText.addActionListener( 
        new ActionListener(){
        public void actionPerformed(ActionEvent event){
            sendMessage(event.getActionCommand());
            userText.setText(""); //Resets editable text field after you send message
        }
        }
    );
    add(userText, BorderLayout.SOUTH);//places user text input (JTextArea) field at bottom
    chatWindow = new JTextArea(15,30); //displays conversation
    add(new JScrollPane(chatWindow));
    chatWindow.setLineWrap(true); //wraps lines when they outgrow the panel width
    chatWindow.setWrapStyleWord(true); //ensures that above line wrap occurs at word end
    setSize(400,320);
    this.setLocationRelativeTo(null); //places frame in center of screen
    setVisible(true); //set visible on screen
    }

    //3.Setup and Run the Server
    public void StartRunning(){
        try{
            server = new ServerSocket(6789, 100);
            //Client connects at Port # 6789
            //100 = QueueLength - the backlog of clients who can wait at port #6789 to connect to the Server

            //while(true) ... means this while loop is going to run forever
            while(true){
                try{
                    waitForConnection();
                    setupStreams();
                    whileChatting(); //allows messages to pass back and forth through streams
                }catch(EOFException eofException){

                    //connect and have conversation
                    //Display timestamp for disconnection
                    showMessage("\n\n" + fullTimeStamp);
                    showMessage("\nConnection terminated by SERVER! "); //displays end of stream/connection


                }finally{
                    closeCrap();
                }
            }
        }catch(IOException ioException){
            ioException.printStackTrace(); //Displays info where there's an error!
    }
    }

        //4. wait for connection method, then display connection info
        private void waitForConnection() throws IOException{
            showMessage("\n SERVER : Waiting for user(s) to connect... \n "); //tells user Server is waiting for a connection
            connection = server.accept();
            //socket "connection" will accept connections. Creates a socket for each new connection.
            showMessage("Connected with " +connection.getInetAddress().getHostName()); //displays IP address and hostname

        }

        //5. setup streams method.. get streams to send and receive data
        private void setupStreams() throws IOException{
            output = new ObjectOutputStream(connection.getOutputStream());
            //creates pathway to allow connection to whichever computer the 'connnection' socket created.
            output.flush(); //clears data that gets left over in buffer when you try to connect to someone else. Flushes it over to the other person.
            input = new ObjectInputStream(connection.getInputStream());
            //no flush here, because you cannot flush someone else's stream
            showMessage("\n Streams are now setup! \n");

        }

        //6. during conversation method

        private void whileChatting() throws IOException{

            //Display timestamp for connection
            showMessage("\n" + fullTimeStamp);

            String message = "You are now connected! \n ";
            sendMessage(message);
            ableToType(true); //will allow user to type into text box after a connection
            String timeStamp = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date());//timestamp

            do{
                try{
                    message = (String) input.readObject(); //read incoming message as a String and store in 'message' variable.
                    showMessage("\n" + message);//displays each message you receive on a new line
                }catch(ClassNotFoundException classNotFoundException){
                    showMessage("/n I don't know what object the user has sent!");
                }

            //***broken by timestamp?***    
            }while(!message.equalsIgnoreCase("CLIENT " + "[" + timeStamp  + "]" + ": " + "END")); //allows conversation until Client enters "END"

        }

        //7. Close Crap method - close streams and sockets after you are finished chatting
        private void closeCrap(){
            showMessage("\n\n Closing connections... \n");
            ableToType(false);
            try{
                output.close(); //close your stream to other users
                input.close(); //close incoming streams
                connection.close(); //close the socket

            }catch(IOException ioException){
                ioException.printStackTrace();
            }
}
        //8. send message method - send message to client
        private void sendMessage(String message){
            try{

                //writeObject method is built into Java.

                String timeStamp = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date());//timestamp
                output.writeObject("SERVER" + " [" + timeStamp + "]" + ": " + message);
                showMessage("\nSERVER" + " [" + timeStamp + "]" + ": " + message); //shows the ouput message in our conversation window
                output.flush();
            }catch(IOException ioException){
                chatWindow.append("ERROR: Unable to send message!");
            }
        }

        //9. updates chatWindow - instead of creating entirely new GUI each time
        private void showMessage(final String text){
        SwingUtilities.invokeLater(
                new Runnable(){
                    public void run(){
                        chatWindow.setEditable(false); //disallows text editing in chatWindow
                        chatWindow.append(text); //appends text, which was passed in from above
                    }
                }
                );  
}
        //10. Lets user type
        private void ableToType(final boolean tof){
            SwingUtilities.invokeLater(
                    new Runnable(){
                        public void run(){
                            userText.setEditable(tof); //passes in 'true'
                        }
                    }
                    );  

        }
}

The way ServerSockets work in java is that clients that want to connect get queued until you can ServerSocket.accept() which dequeues the first one and returns it. ServerSockets在Java中的工作方式是使要连接的客户端排队,直到您可以将第一个服务器出队并返回它的ServerSocket.accept()为止。 Therefore, for multiple clients to be connected to a single server, you will need to call accept multiple times. 因此,要使多个客户端连接到单个服务器,您将需要多次调用accept。 Accept will also block until a client is actually available, as you may know. 如您所知,Accept也会阻塞,直到客户端实际可用为止。

You need to create a connection handler thread that handles a single client connection, and then spawn threads off whenever a new client is connected. 您需要创建一个用于处理单个客户端连接的连接处理程序线程,然后在连接新客户端时关闭线程。 Basically 基本上

while(true){
    Socket s=server.accept();
    new ConnectionHandlerThread(s).start();
    // write the ConnectionHandlerThread yourself
}

I would write some more detailed code for you, but I'm on mobile sorry. 我会为您编写一些更详细的代码,但是对不起,我正在使用移动设备。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM