Secular wanderer: a programmer who focuses on technical research

Back to the previous point

There is no actual case of the theoretical basis is playing rogue, so today is mainly want to through the case here can let you deepen the understanding of the previous

In this section we will implement a point-to-point chat applet step by step

Socket implementation in Java

InetAddress

InetAddress is Java’s encapsulation of an IP address. This class is the base class that both ServerSocket and DatagramSocket depend on

InetAddress cannot be initialized with new and can only be called with the static method it provides:

// Get the local address
InetAddress localHost = InetAddress.getLocalHost();
Copy the code

Here are some methods of InetAddress:

// Host name: desktop-atg4kke
System.out.println("Host name:" + localHost.getHostName());

// IP address: 192.168.87.1
System.out.println("IP address:" + localHost.getHostAddress());

// Normal: true
System.out.println("Normal or not:" + localHost.isReachable(5000));
Copy the code

Here’s the output from my test,

The isReachable() method is used to check if the address isReachable. From there, we can do some health checks, such as:

// Get the InetAddress object by host IP or domain name
InetAddress inetAddress = InetAddress.getByName("192.168.87.139");
System.out.println("Normal or not:" + inetAddress.isReachable(5000));
Copy the code

Try to connect to the host as much as possible within 5 seconds. If not, the host is considered unavailable due to firewall and server configuration

Of course, doing a health check is a low point, and certainly not done in a production environment

PS: Network operations in production environments do not use the stuff in this section, and most of the time use Netty

ServerSocket

ServerSocket is a ServerSocket based on TCP/IP protocol implementation

Initialize the

Usually we build like this:

ServerSocket serverSocket = new ServerSocket(9999);

ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(9999));
Copy the code

This completes the initialization of the server and binds port 9999

Waiting for the connection

If the client wants to establish a connection to the ServerSocket, we need to do so

for(;;) {
    Socket socket = serverSocket.accpet();
    // Socket[addr=/0:0:0:0:0:0:0:1,port=62445,localport=9999]
    System.out.println(socket);
}
Copy the code

Accpet () listens for connections to ServerSocket, which is a blocking method that waits for connections to come in

If there is an incoming connection, we can return the value to get the current incoming Socket

communication

Data is actually transmitted in the same way as IO streams, but we can only get byte streams:

InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
Copy the code

InputStream reads data and OutputStream writes data. These basic operations were introduced in IO streams and won’t be covered here

In order to improve efficiency, we can use the wrapper flow or the processing flow, which was introduced earlier

Complete small example

In fact, the ServerSocket key introduction is finished, let’s do a small example:

  • When a client is connected, return to the client:Hello World
public class _ServerSocket {
    // Stores the mapping between the requesting client and the Socket
    static Map<String, Socket> MAP = new HashMap<>(); 
    
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket();
            serverSocket.bind(new InetSocketAddress(9999));

            for(; ;) { String token = UUID.randomUUID().toString().replace("-"."").toLowerCase();
                
                Socket socket = serverSocket.accept();
                / / the correspondingMAP.put(token, socket); outHtml(socket); }}catch(IOException e) { e.printStackTrace(); }}public static void outHtml(Socket socket) {
        OutputStream outputStream = null;
        try {
            outputStream = socket.getOutputStream();
            outputStream.write(("HTTP / 1.1 200 OK \ n \ nHello World").getBytes("UTF-8"));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null! = outputStream) {try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
Copy the code

HTTP / 1.1 200 OK \ n \ nHello World \ n

This is the HTTP return type, preceded by the Response fixed format, and Hello World is the actual return, so that our ServerSocket can be accessed through the browser

Socket

The Socket belongs to the client Socket. Only after the connection is established with the server Socket can other operations be performed. The way of using the Socket is very simple

Establish a connection

Socket socket = new Socket("127.0.0.1".9999);

// Verify that the connection is successful
if (socket.isConnected()) {
    System.out.println("Connection to server successful");
}
Copy the code

That’s one way to construct it, but more often than not, it’s this way

After the connection to the server is successfully established, the subsequent operation is the same as the ServerSocket communication step, so there is no more nonsense here

Let’s use a complete example to reinforce this

Example: TCP point-to-point chat

The service side

public class Server {
    /** * associate the client id with the socket */
    private static final Map<String, Socket> SOCKET_MAP = new HashMap<>();
    /** * reverse correlation, used to get the identity */
    private static final Map<Socket, String> SOCKET_TOKEN_MAP = new HashMap<>();

    public static void main(String[] args) throws IOException {
        /**
         * 开启ServerSocket并监听9999端口
         */
        ServerSocket serverSocket = new ServerSocket(9999);

        for (;;) {
            /** ** Waiting for the client to connect */
            Socket socket = serverSocket.accept();

            /** * IO reads are blocking methods, so new threads need to be started, which can be optimized to thread pool */
            new Thread(() -> {
                try {
                    saveToMap(socket);
                    getClientMsg(socket);
                } catch(IOException e) { e.printStackTrace(); } }).start(); }}/** * bind SOCKET */
    private static void saveToMap(Socket socket) throws IOException {
        String token = StringUtil.uuid();
        SOCKET_MAP.put(token, socket);
        SOCKET_TOKEN_MAP.put(socket, token);

        System.out.println("-- Client connected successfully, no. :" + token);
        System.out.println("Current user :" + SOCKET_MAP.size());

        /** * Because there is no login, the client is told its identity */
        send(token, token, token);
    }

    /** * gets the message from the client and sends it to the specified client */
    private static void getClientMsg(Socket socket) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line = "";
        while((line = reader.readLine()) ! =null) {
            // After reading a line, send it from heresend(socket, line); }}/** * Send message */
    private static void send(Socket socket, String line) throws IOException {
        String[] s = line.split("#");
        final String from = SOCKET_TOKEN_MAP.get(socket);
        send(s[0], s[1], from);
    }

    /** * Send message *@param token
     * @param msg
     * @paramFrom here is displayed on the target client@throws IOException
     */
    private static void send(String token, String msg, String from) throws IOException {
        Socket sk = SOCKET_MAP.get(token);

        if (null == sk)
            return;

        String s = from + ":" + msg;
        System.out.println("-- Send to client :" + s );
        // Character stream output
        BufferedWriter writer = new BufferedWriter(newOutputStreamWriter(sk.getOutputStream())); writer.write(s); writer.newLine(); writer.flush(); }}Copy the code

The client

public class Client {

    public static void main(String[] args) throws IOException {
        /** * Connect to the server */
        Socket socket = new Socket("127.0.0.1".9999);

        /** * open a new thread to read messages, which can be optimized */
        new Thread(() -> {
            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String line = "";
                while(StringUtil.isNotBlank(line = reader.readLine())) { System.out.println(line); }}catch (IOException e) {
                e.printStackTrace();
            }
        }).start();

        /** * Writes a message from the console and sends it */
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNext()) { String next = scanner.next(); send(next, socket); }}private static void send(String msg, Socket socket) throws IOException {
        BufferedWriter writer = new BufferedWriter(newOutputStreamWriter(socket.getOutputStream())); writer.write(msg); writer.newLine(); writer.flush(); }}Copy the code

The code has been tested and the comments are very clear, so you can try it out and follow the format of the # message to start a peer-to-peer chat.

If you want a group chat:

  • Simply save the Socket to the collection and loop through the collection

For a long time did not write Socket chat program, almost gave up

Next time use Netty to write, Netty is much more convenient than Socket

DatagramSocket

DatagramSocket is a socket used to send and receive datagram packets. It is implemented under UDP protocol. According to the official introduction of the class:

A datagram socket is a sending or receiving point for a packet delivery service. Each packet sent or received on a datagram socket is individually addressed and routed. Multiple packets sent from one machine to another may be routed in different ways and may arrive in any order

We can also understand the characteristics of UDP protocol.

DatagramPacket

This class represents a datagram packet and is used to pass and receive data in the DatagramSocket, for example:

  • Receive data
byte[] buffer = new byte[1024];
DatagramPacket p = new DatagramPacket(buffer, buffer.length);
Copy the code
  • To send data
DatagramPacket p = new DatagramPacket("123".getBytes(), "123".getBytes().length, InetAddress.getByName("localhost"), 9999);
Copy the code

To send data out, the DatagramPacket must specify the IP address and port number of the receiving end

Now let’s see how it works. Okay

Initialize the

DatagramSocket socket = new DatagramSocket(9999);

DatagramSocket s = new DatagramSocket(null);
s.bind(new InetSocketAddress(9999));
Copy the code

You can do initialization either way, what’s the difference

Receives the message

byte[] buffer = new byte[1024];
DatagramPacket p = new DatagramPacket(buffer, buffer.length);

socket.receive(p);

System.out.println(new String(p.getData(), 0, p.getLength()));
Copy the code

A byte[] is constructed from the receive parameter of the DatagramPacket and receive() is called so that the message is received

Receive () is a blocking method that continues execution until a message is received

Send a message

DatagramPacket p = new DatagramPacket("123".getBytes(), "123".getBytes().length, InetAddress.getByName("localhost"), 9999);

socket.send(p);
Copy the code

Construct the send packet and call the send() method to finish sending the packet

UDP does not need to connect, directly through the IP+PORT mode can send data

Example: UDP chat

public class _DatagramPacket {

    public static void main(String[] args) throws IOException {
        // Get the port to bind and the port to send data from the command line
        DatagramSocket datagramSocket = new DatagramSocket(Integer.parseInt(args[0]));
        
        System.out.println("Started");

        new Thread(() -> {

            byte[] buffer = new byte[1024];
            DatagramPacket p = new DatagramPacket(buffer, buffer.length);
            try {
                for (;;) {
                    // Build the received data
                    datagramSocket.receive(p);
                    System.out.println(p.getPort() + ":" + new String(buffer, 0, p.getLength())); }}catch (IOException e) {
                e.printStackTrace();
            }
        }).start();

        Scanner scanner = new Scanner(System.in);
        DatagramPacket p = new DatagramPacket(new byte[0].0.new InetSocketAddress("127.0.0.1", Integer.parseInt(args[1)));while (scanner.hasNext()) {
            String next = scanner.next();
            // Build send packetp.setData(next.getBytes()); datagramSocket.send(p); }}Copy the code

There are defects, the space will be newline, here you go to modify

The last word

Here, about the Socket programming aspects of the thing is finished, there is no introduction to a lot of API methods, these in the use of time to see the same.

Here is the directory where Java.net is located:

Click here to see