Come on, this blog today teaches you how to write an online chat room by hand, and you can't cut me off.
1. Functional Design
-
Achieve online communication between two users without group functionality.
-
Keyboard entry
-
console output
2. Technical Analysis
- The following analysis applies to both UDP and TCP
- First, we can easily write out two functions Send and Receive, one to listen for keyboard input and one to listen for connection input. How can we do this? Use a dead loop in each of these two functions to determine if the input is an end condition, jump out of the loop, close the connection, or listen all the time. This part of the code can see the attachment.
- So how do we get users to receive and send? Someone said we could let a user have both Send and Receive methods, and then let the user execute two methods separately! NONONONO!Too Yang Too Sen Broken! Things are not that simple, because the above uses a dead loop, so if you first execute the receive, it must not be sent, if you first send, it must not be received!
- From the analysis of 2, we have to synchronize the receive and send! That's right, it's multi-threaded!!! Let each user open two threads, keep receiving and sending, so that a connection can be established. Then just put the function in the run function.
3. Specific implementation
3.1. Implementation of UDP
//Send Method Implementation Class package main.UdpChat; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.*; public class SendMessage implements Runnable { //Look primarily at the run method public int port;//Your own port name public int toPort;//To which port public String toIp;//To which address public DatagramSocket socket = null; public BufferedReader reader = null; public SendMessage(int port, int toPort, String toIp) { this.port = port; this.toPort = toPort; this.toIp = toIp; try { socket = new DatagramSocket(curport); } catch (SocketException e) { e.printStackTrace(); } } @Override public void run() { //Sender while(true)//Non-stop hair { try { reader = new BufferedReader(new InputStreamReader(System.in)); String data = reader.readLine();//Get the input, notice that there is no \n in the end of the data here, what is entered in the keyboard is what. Here the keyboard input is blocked, and when there is no input, it will wait here and not go down. byte[] datas = data.getBytes(); DatagramPacket packet = new DatagramPacket(datas,0,datas.length, new InetSocketAddress(toIp,toPort));//Pack socket.send(packet);//send attention! send here is a packet, different from Tcp!!! if(data.equals("bye")) break; }catch (Exception e) { System.out.println(e.getStackTrace()); } } socket.close();//Close } }
//Receive Method Implementation Class package main.UdpChat; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class ReceiveMessage implements Runnable { public int port;//Own Port public DatagramSocket socket = null; public String who;//Who sent it to me? public ReceiveMessage(int port,String who) { this.port = port; this.who = who; try { socket = new DatagramSocket(port); } catch (SocketException e) { e.printStackTrace(); } } @Override public void run() { while (true) { try { byte[] container = new byte[1024]; DatagramPacket packet = new DatagramPacket(container, 0, container.length);//Pack socket.receive(packet);//receive data byte[] data = packet.getData(); String receivedata = new String(data,0,data.length); System.out.println(who + " :" +receivedata);//print data if(receivedata.equals("bye")) break; }catch (Exception e) { System.out.println(e.getStackTrace()); } } socket.close(); } }
Now that we've created the method classes, we're going to set up users to use the run methods in these two classes
//Create User A package main.UdpChat; public class AChat { public static void main(String[] args) { //Create a new thread to execute when the cpu has free time //New send function, port 7777, port 8888 to localhost new Thread(new SendMessage(7777,8888,"localhost")).start(); //Create a new listen-receive function to listen for information from port 9999 and identify the port as the place where B is connected. new Thread(new ReceiveMessage(9999,"B")).start(); } }
//Create User B package main.UdpChat; public class BChat { public static void main(String[] args) { //Same as A. My own port is 5555, sent to 9999 localhost new Thread(new SendMessage(5555,9999,"localhost")).start(); //Listen for information from port 8888 and confirm that port is connected to A new Thread(new ReceiveMessage(8888,"A")).start(); } }
3.2. Implementing effect of UDP
Start AChat and BChat:
Two small green dots light up to indicate the start is complete.
Effect:
That's how UDP is implemented. The main idea comes from the theory of madness!
3.2. Implementing effect of UDP
Start AChat and BChat:
[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-wd25LbZV-1634145311514)(C:/Users/13931/Desktop/%E5%AE%9E%E7%94%A8txt/resources/image-20211014004418255.png)]
Two small green dots light up to indicate the start is complete.
Effect:
[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-5g 83sofc-1634145311545) (C:/Users/13931/Desktop/%E5%AE%9E%E7%94%A8txt/resources/image-202110004537383.png)]
[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-0WqlqX04-1634145311547)(C:/Users/13931/Desktop/%E5%AE%9E%E7%94%A8txt/resources/image-20211014004550065.png)]
That's how UDP is implemented. The main idea comes from the theory of madness!
3.3. Implementation of TCP
- Consistent implementation first, multithreading is still used, with both receive and send enabled. The main difference between the two is in the construction method. Since UDP is sent and received through a package, no line breaks need to be added, but TCP requires
- Secondly, to improve performance, we use the implementation subclass of the BufferedReader class because the length of the array cannot be fixed or fixed.
- The TCP accept method is blocked and waits for a connection when it cannot be received. See the code first if you don't understand this sentence.
//Send Method Implementation Class package main.Tcp; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.util.Scanner; public class SendMsg implements Runnable{ private String toIp;//Address to send private int toPort;//Port to Send private Socket socket;//Sender private OutputStream os;//io Flow public SendMsg(String toIp, int toPort) { this.toIp = toIp; this.toPort = toPort; try { socket = new Socket(toIp,toPort); os = socket.getOutputStream(); os.write("Connection Successful\n".getBytes()); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { while (true) { try { Scanner sc = new Scanner(System.in); String data = sc.nextLine() + "\n";//Keyboard input, blocking, you must add a line break here, or the receiver cannot write out of the cache because it uses the BufferedReader class. if(data.equals("bye"))//If bye is entered, disconnect. break; os.write(data.getBytes()); } catch (IOException e) { e.printStackTrace(); } } try { os.close(); socket.close(); }catch (Exception e){ System.out.println(e.getMessage()); } } }
//Method Implementation Class for Receive Receiver package main.Tcp; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; public class Receive implements Runnable { private int port;//Current Port private String from;//Where do you come from? private ServerSocket serverSocket;//Server private Socket socket;//Clients received from the server private BufferedReader br;//flow public Receive(int port, String from) { this.port = port; this.from = from; try { serverSocket = new ServerSocket(port); socket = serverSocket.accept(); br = new BufferedReader(new InputStreamReader(socket.getInputStream())); } catch (Exception e) { System.out.println(e.getMessage()); } } @Override public void run() { String data = null; while (true) { try { data = br.readLine();//Read out the data in the buffer stream and note!!! Because ReadLine is used here, writing to the cache is stopped only when line breaks or terminators are encountered, so we add line breaks at the end of every sentence at the sender. System.out.println(from +" :" + data); if(data == "bye") break; } catch (Exception e) { System.out.println(e.getMessage()); } } try { socket.close(); serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } }
//User A package main.Tcp; public class A { public static void main(String[] args) { //Be aware of the start method //Listen for information from 8888, User B new Thread(new Receive(8888,"user B")).start(); //Send information to port 9999 via localhost new Thread(new SendMsg("localhost",9999)).start(); } }
//User B package main.Tcp; import java.util.TreeMap; public class B { public static void main(String[] args) { new Thread(new SendMsg("127.0.0.1",8888)).start(); new Thread(new Receive(9999,"user A")).start(); } }
3.4. Implementation results of TCP
Initialization
results of enforcement
This is the implementation of TCP
4. Summary
- Points of Attention
- Use BufferedReader.readline();Write only when line breaks are read.
- The port name must match.