Multiplayer chat room
1, Function introduction
When each client connects to the server, it starts to send messages to the server. When receiving the client's connection, the server first outputs who entered the chat room, and then forwards the messages sent by the client to other clients to realize the function of group chat, Finally, the multi-functional (fast, real-time, multi-person) multi-person chat is realized to bring users a better experience.
2, Design conception
-
Design the interface of client and server
- Input box and output box
- User nickname
- Message time
- Add scroll bar
- Add button
- Setting of function keys
- Display of user access
-
Interaction between server and client
-
First, the server should instantiate a ServerSocket object and wait for the client to connect with the accept() method.
It is worth noting here that the accept() method in the ServreSocket class is a blocking method, that is, the accept() method will always wait in a blocking manner before obtaining the connection of the client, and will not let the following code execute until the connection of the client is obtained. -
While the server is waiting, we need to establish a client and apply for a connection to the server. Then, in the client code, we need to instantiate a Socket object, which should have the same port number as the server ServreSocket, so as to ensure accurate connection to the server. After successfully instantiating and creating the Socket object, it is equivalent to successfully establishing a connection with the server (provided that the requested server object has been created and is waiting for the accept() method).
- After the client successfully applies for a connection, we return to the accept() method on the server. After the accept() method successfully obtains the connection application, the returned value is a Socket object, which is the connection to the client.
-
After the TCP connection between the client and the server is successfully established through the Socket object and ServerSocket object, we will start the information exchange between the server and the client through the implementation of IO flow: the input flow and output flow in the corresponding direction can be obtained through the getInputStream() method and getoutputstream() method in the Socket class.
- The server can write information to the client through the OutputStream stream created by using getoutputstream() method on the Socket object obtained by accept(). Similarly, the InputStream stream obtained by using getInputStream() method on the Socket object can read information from the client. And vice versa.
-
Optimize interface
- Solve subsequent bugs
- Make the user interface simpler and less cumbersome
3, Experimental results show
-
Server port
-
Client port
-
Message interaction
4, Specific code and steps
-
Interface design
1. Client
public void init(){ this.setTitle("Client window"); this.add(sp,BorderLayout.CENTER); this.add(tf,BorderLayout.SOUTH); this.setBounds(300,300,300,400); //Set listening for input box tf.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String strSend = tf.getText(); //Gets the text in the input box if(strSend.trim().length()==0){ //If the input box is empty, no operation will be performed(inspect) return; } //strSend Method of sending server send(strSend); // Send the text content to the sending server method tf.setText(""); // The text disappears in the text box after entering } }); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Close windows and programs ta.setEditable(false); //You cannot type in the display box tf.requestFocus(); //Cursor focus try { s= new Socket(CONNSTR,CONNPORT); //Indicates that you are connected to the server isConn = true; } catch (UnknownHostException e1) { // TODO Automatically generated catch block e1.printStackTrace(); } catch (IOException e1) { // TODO Automatically generated catch block e1.printStackTrace(); } this.setVisible(true); //Display the constructed data model new Thread(new Receive()).start();//Start multithreading
2. Server side
public ServerChat(){ this.setTitle("Server side"); this.add(sp,BorderLayout.CENTER); btnTool.add(startBtn); btnTool.add(stopBtn); this.add(btnTool,BorderLayout.SOUTH); this.setBounds(0,0,500,500); if(isStart){ //Determine whether the server is started serverta.append("Server started\n"); }else{ serverta.append("The server has not started yet. Please click the button to start it\n"); } //Assign listening to the window close key this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { isStart = false ; try { if (ss!=null){ ss.close(); } System.out.println("Server stopped!"); serverta.append("Server Disconnected"); System.exit(0); //The same is true for the close button below the exit program } catch (IOException e1) { // TODO Automatically generated catch block e1.printStackTrace(); } } }); //Press newplus monitor to turn it off stopBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { if (ss!=null){ ss.close(); //Close the server connection port isStart = false; } System.exit(0); serverta.append("Server Disconnected"); System.out.println("Server stop!"); } catch (IOException e1) { // TODO Automatically generated catch block e1.printStackTrace(); } } }); //Set a monitor for the start button startBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Successfully started"); try { if(ss == null){ ss= new ServerSocket(PORT); //Create a server port number } isStart = true; //The start condition becomes true serverta.append("The server has started!"+"\n"); } catch (IOException e1) { // TODO Automatically generated catch block e1.printStackTrace(); } } }); this.setVisible(true); //Display the constructed data model startServer(); }
-
Interaction between client and server port
1. Establish a channel between the client and the server
dos = new DataOutputStream(s.getOutputStream()); //Establish a send pipeline
2. Create a port number for the client on the server
try{ try{ ss = new ServerSocket(PORT); //Create port number isStart=true; }catch (IOException e2){ e2.printStackTrace(); } //Can receive connections from multiple clients while(isStart){ //Here, whether to start is used as the loop judgment condition Socket s =ss.accept(); //Wait here to receive the information of the client. Connect a client to a server interface ccList.add(new ClientConn(s)); //Each one adds information to the collection System.out.println("A client connects to the server:"+s.getInetAddress()+"/"+s.getPort()); serverta.append("A client connects to the server:"+s.getInetAddress()+"/"+s.getPort()+"\n"); }
3. The client sends a message
public void send(String str){ //Get text to send try { dos = new DataOutputStream(s.getOutputStream()); //Establish a send pipeline dos.writeUTF(str); } catch (IOException e) { // TODO Automatically generated catch block e.printStackTrace(); } }
4. The server receives messages
public void run() { try { DataInputStream dis =new DataInputStream(s.getInputStream()); //In order to enable the server to receive multiple sentences from each client while(isStart){ //Here, whether to start is used as the loop judgment condition String str =dis.readUTF(); //Receive text System.out.println(s.getLocalAddress()+"|"+s.getPort()+"say:"+str+"\n");//Display on console serverta.append(s.getLocalAddress()+"|"+s.getPort()+"say:"+str+"\n"); //Displayed on the server side String strSend = s.getLocalAddress()+"|"+s.getPort()+"say:"+str+"\n"; //ergodic ccList call send Method receives information on the client, which is received by multiple threads(Multithreaded send message) java.util.Iterator<ClientConn> it = ccList.iterator(); while(it.hasNext()){ ClientConn o = it.next(); o.send(strSend); } } } catch (SocketException e){ System.out.println("A client is offline\n"); serverta.append(s.getLocalAddress()+"|"+s.getPort()+"The client is offline\n"); //Establish pipeline for sending }catch (IOException e) { // TODO Automatically generated catch block e.printStackTrace(); } }
5. The server sends a message
public void send(String str){ try { DataOutputStream dos = new DataOutputStream(this.s.getOutputStream()); dos.writeUTF(str); } catch (IOException e) { // TODO Automatically generated catch block e.printStackTrace(); } }
6. The client receives messages
class Receive implements Runnable{ @Override public void run() { try { while(isConn){ DataInputStream dis = new DataInputStream(s.getInputStream()); String str = dis.readUTF(); ta.append(str); } } catch (SocketException e) { System.out.println("Server terminated unexpectedly!"); ta.append("Server terminated unexpectedly!\n"); }catch (IOException e) { // TODO Automatically generated catch block e.printStackTrace(); } } }
7. Traverse the message sent by the client (to prevent the message from being sent back to itself)
java.util.Iterator<ClientConn> it = ccList.iterator(); while(it.hasNext()){ ClientConn o = it.next(); o.send(strSend); }
5, Summary
- After consulting the blogger blog and related documents to complete the multi person chat room project, although our code ability is not very obvious, but after this campaign, my java skills deepened, and the design and thinking of the project have a certain breadth and depth.
- After completing the multi person chat project, the biggest help to me is to let me understand the concept of an intermediate level Socket
-
We always thought that after the client sends a message, the server must process it immediately, but in fact, some intermediate forwarding processes can be set, such as message queue to save the data in the sending process. This can improve the response rate and stability of the system, so as to avoid some uncertain factors, such as decoupling and during message peak, If the step frequencies of the sender and the receiver are inconsistent, intermediate forwarding can make up for the inconsistency between the step frequencies of producers and consumers
- In the process of writing server code, there are pits everywhere, and the reported errors should be handled one by one to achieve better optimization
Team members:
Liu Longjun, Guo Runfang, Hui Wenkai, Xing Runhu
Link: https://pan.baidu.com/s/1kP3PY71-Ev-e_ulc7MNomg
Extraction code: 4ezx