java socket realizes the server, and the client has simple network communication. Chat

Posted by Byron on Mon, 04 May 2020 03:09:22 +0200

There are some serious bug s in the code written before to realize simple network communication. Write in detail later.

According to the last code, mainly increased the user registration, login page, and realized the real-time display of the current login status of the number of people. And solve some bug s not found last time. (refer to previous notes for main function codes https://www.cnblogs.com/yuqingsong-cheng/p/12740307.html)

 

To achieve user registration and login, I need to use database, because I am mainly studying Sql Server. Sql Server also supports Linux system. Then install and configure under Ubuntu system of my computer.

Link: https://docs.microsoft.com/zh-cn/sql/linux/quickstart-install-connect-red-hat?view=sql-server-ver15     

Sql Server official website has installation guidance documents for each system, so follow the normal installation steps and install everything normally.

There was a problem putting it on the server. Alicloud student server has 2G memory (for activities and student ID, it's really delicious). But memory is a little bit small. SqlServer requires at least 2G memory. So we can only give up SqlServer and turn to Mysql.

Also install according to MySql's official guidance document. However, remote connection requires some "messy" configuration, so we started to "connect to Baidu" and recommended a solution, https://blog.csdn.net/ethan__xu/article/details/89320614 It is applicable to mysql8.0 and above.

 

Database part of the solution, began to write about login, registration class. In the login registration part, a new port is opened for socket connection. Because the function is simple, only insert and query statements are used.

The client reads in the login and registration information entered by the user and sends it to the server. The server connects to the database for query / insertion and sends the result to the client.

Instance code

  1 package logindata;
  2 
  3 import java.io.DataInputStream;
  4 import java.io.DataOutputStream;
  5 import java.io.IOException;
  6 import java.net.ServerSocket;
  7 import java.net.Socket;
  8 import java.sql.Connection;
  9 import java.sql.DriverManager;
 10 import java.sql.ResultSet;
 11 import java.sql.SQLException;
 12 import java.sql.Statement;
 13 import java.util.ArrayList;
 14 
 15 public class LoginData implements Runnable{
 16 
 17     static ArrayList<Socket> loginsocket = new ArrayList();
 18     
 19     public LoginData() { }
 20 
 21     @Override
 22     public void run() {
 23         ServerSocket serverSocket=null;
 24         try {
 25             serverSocket = new ServerSocket(6567);
 26         } catch (IOException e) {
 27             e.printStackTrace();
 28         }
 29         while(true) {
 30             Socket socket=null;
 31             try {
 32                 socket = serverSocket.accept();
 33             } catch (IOException e) {
 34                 // TODO Auto-generated catch block
 35                 e.printStackTrace();
 36             }
 37             loginsocket.add(socket);
 38             
 39             Runnable runnable;
 40             try {
 41                 runnable = new LoginDataIO(socket);
 42                 Thread thread = new Thread(runnable);
 43                 thread.start();
 44             } catch (IOException e) {
 45                 // TODO Auto-generated catch block
 46                 e.printStackTrace();
 47             }
 48         }
 49     }
 50 }
 51 
 52 class LoginDataIO implements Runnable{
 53 
 54     String b="false";
 55     Socket socket;
 56     DataInputStream inputStream;
 57     DataOutputStream outputStream;
 58     public LoginDataIO(Socket soc) throws IOException {
 59         socket = soc;
 60         inputStream = new DataInputStream(socket.getInputStream());
 61         outputStream = new DataOutputStream(socket.getOutputStream());
 62     }
 63     
 64     @Override
 65     public void run() {
 66         String readUTF = null;
 67         String readUTF2 = null;
 68         String readUTF3 = null;
 69         try {
 70             readUTF = inputStream.readUTF();
 71             readUTF2 = inputStream.readUTF();
 72             readUTF3 = inputStream.readUTF();
 73         } catch (IOException e) {
 74             e.printStackTrace();
 75         }
 76         
 77 //        System.out.println(readUTF+readUTF2+readUTF3);
 78         
 79         SqlServerCon serverCon = new SqlServerCon();
 80         try {
 81             //Determine whether the connection is logged in or registered. The return value is different.
 82             if(readUTF3.equals("login")) {
 83                 b=serverCon.con(readUTF, readUTF2);
 84                 outputStream.writeUTF(b);
 85             }else {
 86                 String re=serverCon.insert(readUTF, readUTF2);    
 87                 outputStream.writeUTF(re);
 88             }
 89         } catch (SQLException e) {
 90             // TODO Auto-generated catch block
 91             e.printStackTrace();
 92         } catch (IOException e) {
 93             // TODO Auto-generated catch block
 94             e.printStackTrace();
 95         } catch (ClassNotFoundException e) {
 96             // TODO Auto-generated catch block
 97             e.printStackTrace();
 98         }  
 99         
100 //        System.out.println(b);
101     }
102 }
103 
104 
105 class SqlServerCon {
106 
107     public SqlServerCon() {
108         // TODO Auto-generated constructor stub
109     }
110     
111     String name;
112     String password;
113 //    boolean duge = false;
114     String duge = "false";
115 //    String url = "jdbc:sqlserver://127.0.0.1:1433;"
116 //            + "databaseName=TestData;user=sa;password=123456";
117     /**
118      * com.mysql.jdbc.Driver Replace with com.mysql.cj.jdbc.Driver.
119         MySQL 8.0 If the above version does not need to establish an SSL connection, it needs to display close.
120         Finally, you need to set up CST.
121      */
122     //Connect MySql data base url format
123     String url = "jdbc:mysql://127.0.0.1:3306/mytestdata?useSSL=false&serverTimezone=UTC";
124     public String con(String n,String p) throws SQLException, ClassNotFoundException {
125         Class.forName("com.mysql.cj.jdbc.Driver");
126         Connection connection = DriverManager.getConnection(url,"root","uu-7w3yfu?VX");
127 //        System.out.println(connection);
128         
129         Statement statement = connection.createStatement();
130 //        statement.executeUpdate("insert into Data values('china','123456')");
131         ResultSet executeQuery = statement.executeQuery("select * from persondata");
132         
133         //Login nickname password confirmation
134         while(executeQuery.next()) {
135             name=executeQuery.getString(1).trim();
136             password = executeQuery.getString(2).trim();   //"It's important to use this method"  String     trim()      The return value is the string of this string, where all leading and trailing spaces have been removed.
137 //            System.out.println(n.equals(name));
138             if(name.equals(n) && password.equals(p)) {
139                 duge="true";
140                 break;
141             }
142         }
143         statement.close();
144         connection.close();
145 //        System.out.println(duge);
146         return duge;
147     }
148     
149     public String insert(String n,String p) throws SQLException, ClassNotFoundException {
150         boolean b = true;
151         String re = null;
152         Class.forName("com.mysql.cj.jdbc.Driver");
153         Connection connection = DriverManager.getConnection(url,"root","uu-7w3yfu?VX");
154         Statement statement = connection.createStatement();
155         
156         ResultSet executeQuery = statement.executeQuery("select * from persondata");
157         while(executeQuery.next()) {
158             name=executeQuery.getString(1).trim();
159 //            password = executeQuery.getString(2).trim();  
160             if(name.equals(n)) {
161                 b=false;
162                 break;
163             }
164         }
165         
166         //Return to login information
167         if(b && n.length()!=0 && p.length()!=0) {
168             String in = "insert into persondata "+"values("+"'"+n+"'"+","+"'"+p+"'"+")";  //This insert statement is very useful, but I didn't expect it to be better.
169 //            System.out.println(in);
170             statement.executeUpdate(in);
171             statement.close();
172             connection.close();
173             re="login was successful,Please return to login";
174             return re;
175         }else if(n.length()==0 || p.length()==0 ) {
176             re="Nickname or password cannot be empty, please re-enter";
177             return re;
178         }else {
179             re="The nickname user already exists, please re-enter or log in";
180             return re;
181         }
182     }
183 }

 

Because the server needs to be placed in the server, the user interface of the server is deleted.

 1 import file.File;
 2 import logindata.LoginData;
 3 import server.Server;
 4 
 5 public class ServerStart_View {
 6     
 7     private static Server server = new Server();
 8     private static File file = new File();
 9     private static LoginData loginData = new LoginData();
10     public static void main(String [] args) {
11         ServerStart_View frame = new ServerStart_View();
12         server.get(frame);
13         Thread thread = new Thread(server);
14         thread.start();
15         
16         Thread thread2 = new Thread(file);
17         thread2.start();
18         
19         Thread thread3 = new Thread(loginData);
20         thread3.start();
21     }
22     public void setText(String AllName,String string) {
23         System.out.println(AllName+" : "+string);
24     }
25 }

 

For the client, the login interface connects with the service belt through socket, sends the user information and reads the returned information.

Main code:

 1 public class Login_View extends JFrame {
 2 
 3     public static String AllName=null;
 4     static Login_View frame;
 5     private JPanel contentPane;
 6     private JTextField textField;
 7     private JTextField textField_1;
 8     JOptionPane optionPane = new JOptionPane();
 9     private final Action action = new SwingAction();
10     private JButton btnNewButton_1;
11     private final Action action_1 = new SwingAction_1();
12     private JLabel lblNewLabel_2;
13 
14     /**
15      * Launch the application.
16      */
17     public static void main(String[] args) {
18         EventQueue.invokeLater(new Runnable() {
19             public void run() {
20                 try {
21                     frame = new Login_View();
22                     frame.setVisible(true);
23                     frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
24                 } catch (Exception e) {
25                     e.printStackTrace();
26                 }
27             }
28         });
29     }
30 
31 ..................
32 ..................
33 ..................
34 
35 private class SwingAction extends AbstractAction {
36         public SwingAction() {
37             putValue(NAME, "Sign in");
38             putValue(SHORT_DESCRIPTION, "Click to log in");
39         }
40         public void actionPerformed(ActionEvent e) {
41             String text = textField.getText();
42             String text2 = textField_1.getText();
43 //            System.out.println(text+text2);
44 //            boolean boo=false;
45             String boo=null;
46             try {
47                 boo = DataJudge.Judge(6567,text,text2,"login");
48             } catch (IOException e1) {
49                 e1.printStackTrace();
50             }
51             if(boo.equals("true")) {
52                 ClientStart_View.main1();
53                 AllName = text;    //Save user name
54                 frame.dispose();    //void    dispose()    Release this this Window,All native screen resources used by its subcomponents and all its owned children.
55             }else {
56                 optionPane.showConfirmDialog
57                 (contentPane, "Wrong user name or password,Please enter again", "Login failed",JOptionPane.OK_CANCEL_OPTION);
58             }
59         }
60     }
61     
62     private class SwingAction_1 extends AbstractAction {
63         public SwingAction_1() {
64             putValue(NAME, "register");
65             putValue(SHORT_DESCRIPTION, "Click to enter the registration page");
66         }
67         public void actionPerformed(ActionEvent e) {
68             Registered_View registered = new Registered_View(Login_View.this);
69             registered.setLocationRelativeTo(rootPane);
70             registered.setVisible(true);
71         }
72     }
73 }

Connect to the server: the connection method is Boolean type when writing for the first time, but it is only applicable to the information judgment of login. When registering, it is necessary to judge whether the nickname is duplicate, whether the password nickname is empty and other different return information. (the server code has the corresponding judgment String return, parameter 1). So the connection method is changed to String type.

 1 import java.io.DataInputStream;
 2 import java.io.DataOutputStream;
 3 import java.io.IOException;
 4 import java.net.Socket;
 5 import java.net.UnknownHostException;
 6 
 7 public class DataJudge {
 8 
 9     /*public static boolean Judge(int port,String name,String password,String judge) throws UnknownHostException, IOException {
10         
11         Socket socket = new Socket("127.0.0.1", port);
12         DataInputStream inputStream = new DataInputStream(socket.getInputStream());
13         DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
14         
15         outputStream.writeUTF(name);
16         outputStream.writeUTF(password);
17         outputStream.writeUTF(judge);
18         
19         boolean readBoolean = inputStream.readBoolean();
20         
21         outputStream.close();
22         inputStream.close();
23         socket.close();
24         return readBoolean;
25     }*/
26 
27 public static String Judge(int port,String name,String password,String judge) throws UnknownHostException, IOException {
28     
29         //Connect to the server database
30         Socket socket = new Socket("127.0.0.1", port);
31         DataInputStream inputStream = new DataInputStream(socket.getInputStream());
32         DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
33         
34         outputStream.writeUTF(name);
35         outputStream.writeUTF(password);
36         outputStream.writeUTF(judge);
37         
38         String read = inputStream.readUTF();
39         
40         //Login is one-time, so close it in time socket
41         outputStream.close();
42         inputStream.close();
43         socket.close();
44         return read;
45     }
46 }

 

User registration interface, main code:

 1 public class Registered_View extends JDialog{
 2 //    DataJudge dataJudge = new DataJudge();
 3     private JTextField textField_1;
 4     private JTextField textField;
 5     JLabel lblNewLabel_2;
 6     private final Action action = new SwingAction();
 7     
 8     public Registered_View(JFrame frame) {
 9         super(frame, "", true);   //Make the registration dialog box appear on the main panel.
10                 .........
11                 .........
12                 .........
13                 .........
14         }  
15       
16         private class SwingAction extends AbstractAction {
17         public SwingAction() {
18             putValue(NAME, "register");
19             putValue(SHORT_DESCRIPTION, "Click the button to register");
20         }
21         public void actionPerformed(ActionEvent e) {
22             String b=null;  //The registration information string used to receive the return from the server
23             String name = textField.getText();
24             String password = textField_1.getText();
25             try {
26                 b = DataJudge.Judge(6567, name, password, "registered");
27             } catch (IOException e1) {
28                 // TODO Auto-generated catch block
29                 e1.printStackTrace();
30             }
31             
32             lblNewLabel_2.setText(b);
33         }
34     }

 

The user logs in, and the registration part is completed.

Display the number of people in real time, mainly return the generic array size of the storage socket object to the client. This method is called after new client connections are available, and this method is called when a user disconnects.

 1 public static void SendInfo(String rece, String AllName, String num) throws IOException {
 2         DataOutputStream outputStream = null;
 3         for (Socket Ssocket : Server.socketList) {
 4             outputStream = new DataOutputStream(Ssocket.getOutputStream());
 5             outputStream.writeUTF(num);
 6             outputStream.writeUTF(AllName);
 7             outputStream.writeUTF(rece);
 8             outputStream.flush();
 9         }
10     }

 

 

Talk about Bug

Before each disconnection, the user does not close the socket first, and the server does not remove the corresponding socket object, which results in that when the server sends it to each client one by one, the closed socket object cannot be found and a "write error" will be generated.

Therefore, it is necessary to remove the corresponding socket object when the client is disconnected, check the java API document, and find no way to judge whether the client socket is closed at the server.

 

 

Then I thought of the way I looked before. (although it's a bit of a hassle, I can't find a better way.). Then, when you click the exit button or close the panel, send a "by" character to the server. When the server reads this character, it knows that the client is about to disconnect, so as to exit the circular read operation and remove the corresponding socket object.

 1 Panel off event listening
 2 
 3 @Override
 4     public void windowClosing(WindowEvent arg0) {
 5         try {
 6             chat_Client.send("bye");
 7             File_O.file_O.readbye("bye");
 8         } catch (IOException e) {
 9             // TODO Auto-generated catch block
10             e.printStackTrace();
11         }
12     }
 1 Exit button event listening
 2 
 3 private class SwingAction extends AbstractAction {
 4         public SwingAction() {
 5             putValue(NAME, "Sign out");
 6             putValue(SHORT_DESCRIPTION, "close program");
 7         }
 8         public void actionPerformed(ActionEvent e) {
 9             int result=optionPane.showConfirmDialog(contentPane, "Close exit or not", "Exit reminder", JOptionPane.YES_NO_OPTION);
10             if(result==JOptionPane.YES_OPTION) {
11                 try {
12                     chat_Client.send("bye");
13                     File_O.file_O.readbye("bye");
14                     System.exit(EXIT_ON_CLOSE);  //static void    exit​(int status)    Terminate currently running Java Virtual machine. That is, terminate the current program and close the window.
15                 } catch (IOException e1) {
16                     e1.printStackTrace();
17                 }
18             }
19         }
20     }
 1 client send Method, sending finished bye After characters, close socket
 2 
 3 //send()Method to send a message to the server. "Send" button Button click event to call this method
 4     public void send(String send) throws IOException {
 5         DataOutputStream stream = new DataOutputStream(socket.getOutputStream());
 6         stream.writeUTF(Login_View.AllName);
 7         stream.writeUTF(send);
 8         
 9         if(send.equals("bye")) {
10             stream.flush();
11             socket.close();
12         }
13     }
 1. When the server reads the byte character, remove the corresponding socket object and exit the while loop
 2 
 3 if (rece.equals("bye")) {
 4                             judg = false;
 5                             Server.socketList.remove(socket);
 6                             Server_IO.SendInfo("", "", "" + Server.socketList.size());
 7                             /*
 8                              * for (Socket Ssocket:Server.socketList) { DataOutputStream outputStream = new
 9                              * DataOutputStream(socket.getOutputStream()); outputStream = new
10                              * DataOutputStream(Ssocket.getOutputStream());
11                              * outputStream.writeUTF(""+Server.socketList.size());
12                              * outputStream.writeUTF(""); outputStream.writeUTF("");
13                              * System.out.println("8888888888888888"); outputStream.flush(); }
14                              */
15                             break;
16                         }

The same is true for the closing and removal of the file stream, which is not covered in detail.

 

There is another problem with the file stream. Normal login cannot perform the second file transfer. (the first time I wrote it, I probably only tested it once, but I didn't find any bug s. Hahahaha)

It took a long time to solve this problem (too cai, ha ha ha ha ha)

The original code, which is read and sent by the server (you can also take part in the previous essay)

 1   while((len=input.read(read,0,read.length))>0) {
 2                for(Socket soc:File.socketList_IO) {
 3                       if(soc != socket)
 4                              { 
 5                                  output = new DataOutputStream(soc.getOutputStream());
 6                                  output.writeUTF(name);
 7                                  output.write(read,0,len);
 8                                  output.flush();
 9  //                                System.out.println("Start forwarding to client");
10                              }
11                          }
12  //                        System.out.println("implement");
13  //                        System.out.println(len);
14                      }

 

read() method: introduction to API documents

 

 

 

 

When reading to the end of the file, - 1 will be returned. You can see that the while loop ends when len is equal to - 1, but it doesn't work as expected. When debug ging (forgetting the screenshot), it is found that as long as the output stream of the client is not closed, the server will always block after reading the file

While ((len = input. Read (read, 0, read. Length)) > 0), unable to exit, thus unable to forward the next read. Nor can len=-1 be used for break;
Amend to read:
 1 int len=0;
 2 while(true) {
 3     len=0;
 4     if(input.available()!=0)
 5        len=input.read(read,0,read.length);
 6     if(len==0) break;
 7     for(Socket soc:File.socketlist_file) {
 8        if(soc != socket)
 9        {
10           output = new DataOutputStream(soc.getOutputStream());
11           output.writeUTF(name);
12           output.write(read,0,len);
13 //        output.flush();
14 //        System.out.println("Start forwarding to client");
15        }
16 //     System.out.println("One time forwarding"+File.socketlist_file.size());
17     }
18  }

 

That's it

I feel that there are still problems in the transfer and reading of files, and I will continue to improve next time.

Screenshot of some interfaces



Topics: Java socket SQL MySQL