Small instance based on multithreading and Socket

Keywords: Java

                                Client and client communication

How to realize client-side and client-side communication?

First, the server should support connecting multiple clients

Secondly, the communication between the client and the client needs to be transferred through the server, that is, all communication contents need to be sent to the server, and the server sends the data to one client (single chat) or multiple clients (group chat) according to the demand

As mentioned above, both single chat and group chat require the server to send the transit data to the client. But how does the server know which client this message is sent to?

You can do this. When creating a Socket object, you can specify the IP and port, and there are API s to obtain the corresponding IP and port. Then you can use the IP and port to determine each client. When sending messages, you can bring the IP + port that needs to receive information, as shown below

      Custom protocol:           1-192.168.100.3_ 60011 - @ = * = @ Hello!

 

When sending a message, specify the nature of the message: single chat / group chat, and message recipient information: IP_ Port, message body; What if it's a group? We can send the message to all clients connected to the server without considering the IP of receiving the message

The problem comes again. The server needs to save all the client information connected with it. What should I do?

The answer is Map. Using HashMap on the server side and using its key value pair characteristics, when a client is connected to the server, the client IP port and the created Socket information are obtained as follows

       HashMap<String,Socket> map = new HashMap<>();

       map.put("192.168.100.3_60010",socket);

In this way, when you want to communicate, the target IP and port obtained from the message are used as key s, the Socket of the corresponding client is obtained from the Map, and the Socket is used to send data to it

Single chat + group chat

Experimental objective: to achieve single chat and group chat

Create 4 clients with ports 60011600126001360014

       60012 and 60013 are group chat. No matter who chats, they will send data to everyone, that is, the other three clients

       6001160014 is a single chat. They can only chat with each other

client

In fact, the difference between single chat and group chat is whether the client ip and port to receive the message are specified

If the ip and port are specified, the data will be sent to the specified person. If not specified, the data will be sent to everyone

In order to continuously communicate with the server and realize the separation of sending and receiving data (sending before receiving, receiving before sending), the client needs to open two threads, one thread to read data and the other thread to send data

       -->  In the introductory case, that is, the most basic operation, the client needs to send data to the server before receiving data, that is, sending before receiving

Single chat is to specify which client to chat with, so you need to specify the chat port in the program

[60011 client]

This client has a single chat with 60014 client

public class Client1 {
    public static void main(String[] args) throws Exception{
    	System.out.println("---- Client 1 started ----");
    	/**
    	 *  Parameter 1:host - remote host name, or null, indicating loopback address.
    	 *  Parameter 2:port - remote port
    	 *  Parameter 3:localAddr - the local address to bind the socket to
    	 *  Parameter 4:localPort - the local port to bind the socket to 
    	 */
        Socket socket=new Socket("127.0.0.1",10086, InetAddress.getByName("127.0.0.1"),60011);
        // The client starts a thread to read the data sent back by the server
        new Thread(new ClientThreadIn(socket.getInputStream())).start();
        // The client starts a thread to send data to the server, specifying the client ip and port to receive the data
        new Thread(new ClientThreadOut(socket.getOutputStream(),"127.0.0.1_60014")).start();
        
    }
}

[60014 client]

This client has a single chat with 60011 client

public class ClientOneToOne1 {
    public static void main(String[] args) throws Exception{
    	System.out.println("---- Client 4->1 start-up ----");
        Socket socket=new Socket("127.0.0.1",10086,InetAddress.getByName("127.0.0.1"),60014);
        //60014 only chat with 60011
        new Thread(new ClientThreadIn(socket.getInputStream())).start();
        new Thread(new ClientThreadOut(socket.getOutputStream(),"127.0.0.1_60011")).start();
    }
}

[60012 client]

This client chats with all client groups

public class Client2 {
    public static void main(String[] args) throws Exception{
    	System.out.println("---- Client 2 starts ----");
        Socket socket=new Socket("127.0.0.1",10086,InetAddress.getByName("127.0.0.1"),60012);
        new Thread(new ClientThreadIn(socket.getInputStream())).start();
        new Thread(new ClientThreadOut(socket.getOutputStream())).start();
    }
}

[60013 client]

This client chats with all client groups


public class Client3 {
    public static void main(String[] args) throws Exception{
    	System.out.println("---- Client 3 starts ----");
        Socket socket=new Socket("127.0.0.1",10086,InetAddress.getByName("127.0.0.1"),60013);
        new Thread(new ClientThreadIn(socket.getInputStream())).start();
        new Thread(new ClientThreadOut(socket.getOutputStream())).start();
    }
}

[Client - send data thread]


import java.io.*;

public class ClientThreadOut implements Runnable {
	private OutputStream out;// socket output stream
	private String ip_port;// Private chat: ip_port needs a value:

	public ClientThreadOut(OutputStream out) {
		this.out = out;
	}

	public ClientThreadOut(OutputStream out, String ip_port) {
		this.out = out;
		this.ip_port = ip_port;
	}

	public void run() {
		while (true) {
			BufferedWriter bout = new BufferedWriter(new OutputStreamWriter(out));
			try {
				// Input data from the console
				BufferedReader bin = new BufferedReader(new InputStreamReader(System.in));
				String line = null;
				while ((line = bin.readLine()) != null) {
					// Judge whether to chat with ip_port has value
					if (ip_port != null) {
						line = "2-" + ip_port + "@=*=@" + line;  // Custom communication protocol
					} else { // Group chat
						// Group chat: ip and port are invalid, and they are written at will in order to have the same data format
						line = "1-255.255.255.255_65535@=*=@" + line;
					}
					bout.write(line);
					bout.newLine();
					bout.flush();
					if (line.contains("886")) {// Rule 886 is the conclusion
						bout.close();
					}
				}
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}
}

[Client - receive data thread]


import java.io.*;

public class ClientThreadIn implements Runnable {
	private InputStream in;// socket input stream

	public ClientThreadIn(InputStream in) {
		this.in = in;
	}

	public void run() {
		while(true) {
			// Receive the data returned by the server
			BufferedReader bin = new BufferedReader(new InputStreamReader(in));
			try {
				String line = null;
				while ((line = bin.readLine()) != null) {
					System.out.println(line);
				}
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		
	}
}

Server

/**
 * Socket Server
 */
public class Service {
	
	// Map stores the client information connected to the server
    public static final Map<String, OutputStream> outsMap=new HashMap<>();
    
    public static void main(String[] args)throws Exception {
    	System.out.println("---- Server start ----");
    	// Specifies the port to listen on
    	ServerSocket ss=new ServerSocket(10086);
    	// Infinite loop, continuously receiving the data sent by the client to the server
        while(true){
            Socket socket=ss.accept();
            // After receiving the client socket, the server starts a thread to process the socket
            new Thread(new ServerThread(socket)).start();
        }
    }
}

[server thread - process each client]


public class ServerThread implements Runnable {
	private Socket socket;
	private String from_ip_prot;// Source of information
	
	// Initialize thread
	public ServerThread(Socket socket) throws Exception {
		this.socket = socket;
		// Get the ip and port from the socket and splice them into a data
		this.from_ip_prot = socket.getInetAddress().getHostAddress() + "_" + socket.getPort();
		// Take the IP + port of the client as the key, and store the output stream of the client as the value in the map
		// Purpose: in the future, you can get the band client according to the ip + port and communicate with it
		Service.outsMap.put(from_ip_prot, socket.getOutputStream());
	}

	public void run() {
		try {
			// Get the data sent by the client
			BufferedReader bin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			while (true) {
				String line = bin.readLine();
				String messageContent = "";
				if (line.startsWith("1")) {// Group chat
					// Get chat content
					messageContent = line.substring(line.indexOf("@=*=@") + 5);
					messageContent = from_ip_prot + "Group chat:" + messageContent + "\r\n";
					// Remove all clients
					Collection<OutputStream> outs = Service.outsMap.values();
					// Output data to each client
					for (OutputStream out : outs) {
						if (out != null) {
							out.write(messageContent.getBytes());
							out.flush();
						}
					}
				} else if (line.startsWith("2")) {// Private chat
					// Get recipient ip + port
					String to_ip_prot = line.substring(line.indexOf("-") + 1, line.indexOf("@=*=@"));
					// Get chat content
					messageContent = line.substring(line.indexOf("@=*=@") + 5);
					messageContent = from_ip_prot + "Private chat" + to_ip_prot + ": " + messageContent + "\r\n";
					// Send data to recipients
					Service.outsMap.get(to_ip_prot).write(messageContent.getBytes());
					// Echo a copy of the data yourself
					Service.outsMap.get(from_ip_prot).write(messageContent.getBytes());
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}

Finally, let's smooth our thinking

Server code

  1 can receive multiple clients  while() {socket. Accept()}

2 loop once to create a thread to process the socket

3 in order to communicate with each client, you need to save the client socket -- > map of each connection

  4. The server reads the data

      Start to judge whether it is a single chat or a group chat according to the message protocol

      If it's a group chat, get the message content and send a message to everyone

    Where did everyone come from? Because when the client connects to the server, the server stores the client in the map

                      Get everyone from the map and send data to everyone

      If it is a single chat, get the message content and send it to the designated person

    Who is the designated person? Intercept the IP + port of the specified person from the message body

                    Retrieve the specified Socket of the client from the map according to the current key of the Ip + port

          In this way, the specified socket can be used to send messages to the specified client

Client code

  1 connect to the server through ip + port, and specify your own ip and port

  2 create two threads:

    The thread that writes data to the server

      When the client outputs data to the outside, you need to specify the IP and port

      If Ip and port are not specified, group chat is considered, and single chat is specified

      The thread determines whether it is empty according to the IP + port to splice single chat or group chat data

      Send information to the server

    Thread that gets data from the server (read thread)

      Normal IO read data

Posted by garyb_44 on Sun, 26 Sep 2021 18:23:36 -0700