The old article

This article has published 2018.12.29 to www.jianshu.com/p/b04930d2b…

preface

In the last article, we described the transport layer protocols TCP and UDP, but they are just protocols, invisible, so how can we actually transport TCP and UDP? Don’t worry, you will understand after reading this article.

1 summary of the Socket

Socket Chinese meaning for Socket meaning, professional term called Socket, it TCP/IP encapsulation into the call interface for developers to call, that is to say, developers can call socket-related API to achieve network communication. There are socket-related apis in Java, which are mainly divided into UDP transport protocol Socket and TCP transport protocol Socket. This article will describe the sockets based on these two transport protocols in detail.

2 UDP Socket

2.1 Basic Usage

From the previous section, we know that UDP is connectionless. Data can be transmitted by providing the IP address and port number of the peer party. The IP address is responsible for locating the host port. Know the destination IP and destination port number through the UDP Socket in Java can IO transmission, we look at the specific code

** * Sender UDP */ public class UDPSocketSend {public static void main(String[] args) throws IOException { System.out.println("Sender Start..."); DatagramSocket ds = new DatagramSocket(); //2. Encapsulate data String STR ="Did you recite words today"; byte[] bytes = str.getBytes(); // address inetAddress.getByName ("192.168.31.137"); / / parameters: the data, length, the address and port DatagramPacket dp = new DatagramPacket (bytes and bytes. The length, the address, 6666); //3. Send ds.send(dp); Ds.close (); //4. } /** * receiver UDP */ public class UDPSocketReceive{public static void main(String[] args) throws IOException { System.out.println("Receiver Start..."); DatagramSocket ds = new DatagramSocket(6666); //1. Byte [] bytes = new byte[1024]; //2. DatagramPacket dp = new DatagramPacket(bytes,bytes.length); //3. The blocking method ds.receive(dp) is used to send data to packets. InetAddress = dp.getAddress(); // sender IP int port = dp.getPort(); String content = new String(dp.getData(),0,dp.getLength()); System.out.println("address:"+address+"---port:"+port+"---content:"+content); Ds.close (); }}Copy the code

Since I only had a computer next to me, I used port numbers to distinguish the sender from the receiver. Start sender and receiver respectively and let’s look at the printed result sender:

Sender Start...
Copy the code

The receiving party

Receiver Start... Address :/192.168.31.137-- Port :65037-- Content :Did you recite the new wordsCopy the code

After receiving the message successfully, print the sender’S IP and port.

  • Create a UDP socket service first
  • The DatagramSocket encapsulates the data packets, IP addresses, and port numbers based on UDP
  • Send packets through udp socket service
  • Finally, disable the UDP service

Receiver:

  • Create a UDP socket service and specify its own port number
  • Create a DatagramSocket to parse data packets received
  • Receives data into the DatagramSocket
  • Parse data through DatagramSocket
  • Close the service

This is the whole process of sending data through UDP

Note:

  • Because UDP is a connectionless and unreliable transport, the receiver needs to start it before the sender sends the data. Otherwise, the data will not be received. In other words, you must run UDPSocketReceive and then UDPSocketSend.

2.2 Chat Instance

Make a few minor changes to the above example to implement the chat function

public class UDPSocket1 {
    public static void main(String[] args) {
        try {
            new Thread(new Runnable() {
                @Override
                public void run() { try { receive(); } catch (IOException e) { e.printStackTrace(); } } }).start(); send(); } catch (IOException e) { e.printStackTrace(); Private static void receive() throws IOException {system.out.println ("UDOSocket1 Receiver Start..."); DatagramSocket ds = new DatagramSocket(6666); //1. // Infinite loop, always in receive statewhile (trueByte [] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); //3. Send data to ds.receive(dp); String content = new String(dp.getData(), 0, dp.getLength()); System.out.println("UDPSocket1 Receive:"+ content); } } private static void send() throws IOException { //1. DatagramSocket ds = new DatagramSocket(); Br = new BufferedReader(new InputStreamReader(system.in)); String line = null;while((line=br.readLine())! Byte [] bytes = line.getbytes (); // address inetAddress.getByName ("192.168.31.137"); / / parameters: the data, length, the address and port DatagramPacket dp = new DatagramPacket (bytes and bytes. The length, the address, 7777); //3. Send ds.send(dp); } //4. Close the socket service ds.close(); } } public class UDPSocket2 { public static void main(String[] args){ try { new Thread(newRunnable() {
                @Override
                public void run() { try { receive(); } catch (IOException e) { e.printStackTrace(); } } }).start(); send(); } catch (IOException e) { e.printStackTrace(); Private static void receive() throws IOException {system.out.println ("UDOSocket2 Receiver Start..."); DatagramSocket ds = new DatagramSocket(7777); //1. // Infinite loop, always in receive statewhile (trueByte [] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes, bytes.length); //3. Send data to ds.receive(dp); String content = new String(dp.getData(), 0, dp.getLength()); System.out.println("UDPSocket2 Receive:"+ content); } // close the service // ds.close(); } private static void send() throws IOException { //1. DatagramSocket ds = new DatagramSocket(); Br = new BufferedReader(new InputStreamReader(system.in)); String line = null;while((line=br.readLine())! Byte [] bytes = line.getbytes (); // address inetAddress.getByName ("192.168.31.137"); / / parameters: the data, length, the address and port DatagramPacket dp = new DatagramPacket (bytes and bytes. The length, the address, 6666); //3. Send ds.send(dp); } //4. Close the socket service ds.close(); }}Copy the code

Write an infinite loop on the receiving side to keep it in the receiving state. Send sends messages by typing and entering the keyboard, and both endpoints have send and receive functions. Note that receive() executes an infinite loop, so receive() and send() must be on different threads, otherwise messages will not be sent and therefore will not be received. Look at the print: UDPSocket1

UDPSocket Receiver Start...
UDPSocket Receive:hello udp1
heelo udp2
Copy the code

UDPSocket2

UDPSocket2 Receiver Start...
hello udp1
UDPSocket2 Receive:hello udp2

Copy the code

I typed “hello UDp2” in the console of UDPSocket1 and “Hello UDp1” in the console of UDPSocket2. The received and sent messages were exactly the same, and a simple chat function was implemented.

3 TCP Socket

3.1 Basic Usage

TCP is connection-oriented reliable transmission based on client-server. In the last article, we also explained the TCP secure transmission mechanism, which is quite complex. If individuals need to encapsulate TCP protocol, it is obviously difficult for most developers to achieve, so Java also provides tcp-based sockets for developers. Different from UDP, TCP Socket is divided into Socket and ServerSocket corresponding to client and server, the following I use the code to achieve a simple TCP communication function: client:

// Client public class TCPClient {public static void main(String[] args) throws IOException {//1. Socket client = new Socket(); InetSocketAddress = new InetSocketAddress("192.168.31.137", 10000); client.connect(address); OutputStream = client.getOutputStream(); //3. //4. Write data outputStream.write("hello server".getBytes()); //5. Close the stream client.close(); }}Copy the code

First, create a Socket and InetSocketAddress. Then connect the Socket through the connect() method. After the connection is successful, you can obtain the output stream through which data can be transmitted to the server.

Server:

public class TCPServer { public static void main(String[] args) throws IOException { //1. ServerSocket ServerSocket = new ServerSocket(10000); Socket Socket = serversocket.accept (); InputStream = socket.getinputStream (); BufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String line = null;while((line = bufferedReader.readLine())! =null){ System.out.println(line); } //5. Close the stream socket.close(); serverSocket.close(); }}Copy the code

First, create a server Socket and specify the port number. Obtain the linked client Socket through the accept() method, obtain the input stream from the client Socket, and finally read the data transmitted from the client by the input stream. Let’s look at the print on the server side:

hello server
Copy the code

The data is successfully received from the client. Procedure

Note:

A server can communicate with multiple clients at the same time. How does it distinguish between different clients? As we can see from the code above, the server first receives the client Socket with accept(), and then communicates with the stream that the client Socket receives. This also allows the server to differentiate between each client.

3.2 File Transfer Examples

Process: The client uploads a file to the server. After receiving the file, the server saves it and sends a response to the client. Client code

public class TCPUploadClient { public static void main(String[] args) throws IOException { //1. Socket client = new Socket(); InetSocketAddress = new InetSocketAddress("192.168.31.137", 10001); client.connect(address); FileInputStream fis = new FileInputStream("E://girl.jpg"); OutputStream = client.getOutputStream(); Byte [] bytes = new byte[1024]; //5. int len = 0;while((len = fis.read(bytes))! =-1){ outputStream.write(bytes,0,len); } //6. Notify the server that data has been written to client.shutdownOutput(); InputStream InputStream = client.getinputStream (); BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); String line = br.readLine(); System.out.println(line); //8. Close inputStream.close(); fis.close(); client.close(); }}Copy the code

The Socket is created and connected, the local file input stream is read, the file is written to the server, and the data returned by the server is read after successful writing.

Server code

public class TCPUploadServer { public static void main(String[] args) throws IOException { //1. Socket ServerSocket ServerSocket = new ServerSocket(10001); Socket Socket = serversocket.accept (); InputStream is = socket.getinputStream (); File dir = new File("F://tcp"); // Create a folder if it does not existif(! dir.exists()){ dir.mkdirs(); } File file = new File(dir,"girl.jpg");
        FileOutputStream fos = new FileOutputStream(file);
        byte[] bytes = new byte[1024];
        int len = 0;
        while((len = is.read(bytes))! =-1){ fos.write(bytes,0,len); } //5. OutputStream OS = socket.getOutputStream(); os.write("success".getBytes()); Fos. Close (); os.close(); socket.close(); }}Copy the code

Create a Socket and obtain the client Socket and input stream. Create a file in the TCP directory of drive F. Output the data read from the client to the file

Client console

success
Copy the code

So we have achieved a brother client upload file function, or relatively simple, I hope you can also follow the code to knock again.

####3.3 TCP Socket multi-threaded application Careful students may have found that in our example above, a server can only receive a request from a client, which is obviously not in line with the reality, so how to make a server to serve multiple clients at the same time? And then I’m gonna roll out the code

Public class TCPClient1 {public static void main(String[] args) throws IOException {system.out.println ("TCPClient1 Start..."); //1. Create TCP client Socket service Socket client = new Socket(); InetSocketAddress = new InetSocketAddress("192.168.31.137", 10004); client.connect(address); OutputStream = client.getOutputStream(); //3. //4. Write data outputStream.write("Hello my name is Client1".getBytes()); //5. Tell the server to finish sending client.shutdownOutput(); InputStream is = client.getinputStream (); byte[] bytes = new byte[1024]; int len = is.read(bytes); System.out.println(new String(bytes,0,len)); //7. Close the stream client.close(); }} // client 2 public class TCPClient2 {public static void main(String[] args) throws IOException {system.out.println ("TCPClient2 Start..."); //1. Create TCP client Socket service Socket client = new Socket(); InetSocketAddress = new InetSocketAddress("192.168.31.137", 10004); client.connect(address); OutputStream = client.getOutputStream(); //3. //4. Write data outputStream.write("Hello my name is Client2".getBytes()); //5. Tell the server to finish sending client.shutdownOutput(); InputStream is = client.getinputStream (); byte[] bytes = new byte[1024]; int len = is.read(bytes); System.out.println(new String(bytes,0,len)); //7. Close the stream client.close(); }} // Server public class TCPServer {public static void main(String[] args) throws IOException {receive(); } private static void receive() throws IOException { System.out.println("Server Start..."); ServerSocket ServerSocket = new ServerSocket(10004);while (trueSocket Socket = serversocket.accept (); InputStream is = socket.getinputStream (); Byte [] bytes = new byte[1024]; // Obtain data from the input stream to the client. int len = is.read(bytes); System.out.println(new String(bytes,0,len)); OutputStream OS = socket.getOutputStream(); os.write(new String(bytes,0,len).getBytes()); // Close connection socket.close(); }}}Copy the code

Client 1 console

TCPClient1 Start...
Hello my name is Client1
Copy the code

Client 2 console

TCPClient2 Start...
Hello my name is Client2
Copy the code

This enables one server to serve multiple clients

Since the server always processes the request in the main thread, the client request needs to be queued by the server. Example: Client1 makes a single request to the server, and the server does not accept any other request until it responds to Client1. This is obviously illogical. A real server should have concurrent processing. And multithreading can solve this problem, let’s look at the modified server code

public class TCPServer {
    public static void main(String[] args) throws IOException {
        receive();
    }

    private static void receive() throws IOException {
        System.out.println("Server Start..."); ServerSocket ServerSocket = new ServerSocket(10004);while (trueSocket = serversocket.accept (); // Execute client request new Thread(new) by ThreadRunnable() {
                @Override
                public void run() {try {// InputStream is = socket.getinputStream (); Byte [] bytes = new byte[1024]; // Obtain data from the input stream to the client. int len = is.read(bytes); System.out.println(new String(bytes,0,len)); OutputStream OS = socket.getOutputStream(); os.write(new String(bytes,0,len).getBytes()); // Close connection socket.close(); } catch (IOException e) { e.printStackTrace(); } } }).start(); }}}Copy the code

The performance is the same before adding threads, but it is more efficient this way.

conclusion

This article describes sockets based on UDP and TCP. UDP is connectionless, so UDP sockets only need the destination IP address and port to send data. TCP is connection-oriented and based on the client-server mode. It needs to be connected before data transmission and can concurrently process client requests through multi-threading technology. The content of this article is relatively simple, I hope you can put the code in the article to knock over, master Socket at the same time can also make your own UDP and TCP understanding more profound.