Socket Programming for TCP and UDP

Keywords: socket udp TCP/IP

This paper mainly talks about how to use Socket to communicate between server and client based on TCP and UDP, the communication flow and some details in the code, and the differences and reasons between them in the code.

Catalog

1. Socket

2. Communications via TCP

Server Side

Create Welcome socket

Create a dedicated socket

Reading data streams

Sending data streams

* Close socket

Client

Create a socket

* Send data streams

Incoming data streams

* Close socket

3. UDP Communication

Server Side

Create a socket

Receive datagrams

* Send datagrams

* Close socket

Client

Create a socket

* Send datagrams

Receive datagrams

* Close socket

4. Differences between UDP and TCP

1. Socket

First of all, it is clear that a Socket is a local identity that only has a relationship with its own end and that the other end is unknown.

At the same time, a socket identifies a connection relationship between a port of the local IP and a port of another end ip, so this socket has its own IP and port.

It's just like a door at this end. It's an identifying door. We need to send the data we want to send out from this door. At the same time, the data we send to the local port needs to be received in this door. This is the most important role of a socket. It's the socket that receives and sends data. When we need to send relevant data, it's the socket that sends and receives data.When we need to receive data, we also need to call the socket's related method to receive.

And pay attention to the role of socket identification, that is, when we send a message to the other party, the other party knows that we send it, because we send it through this socket, because sockets have a port number and an ip address on them. The same is true, the network is so large, how do you know which ip address and which port to pick up? Because sockets are here, when there is a messageWhen sent, the socket can correspond to the incoming message, and then receive the message through the corresponding socket. < - - This is mainly udp, but in fact tcp is the same, but it is not particularly explicit.

Short steps

Note that this is a one-time operation, that is, a client sends in the past and retracts it, without implementing the operation that the same client sends to the server multiple times. The tcp code is in SocketTest003

2. Communications via TCP

Server Side

Create Welcome socket

1. Create a welcome socket socket, in which you need to pass in the ip address and port number, which is the handshake operation. Note that this socket is only a local identity and is waiting for the client to connect.

Create a dedicated socket

2. You need to call the accept method on the basis of the welcome socket to create a special socket for the sender and yourself, without passing in the ip address and port number, and then use this special socket to read and send.

Reading data streams

3. You need to call the socket's getInputStream method, and then you can call the read method to read the data sent by the client. Here we use the BufferedReader buffer stream to read. Then remember that you need to close the buffer stream at last, but you can't close it directly. Instead, you need to call shutdownInput()Method, so that only the read part is closed, not the socket directly, and close. Then it is important to note that if no data is sent during read, it will be blocked.

Sending data streams

4. You need to call the socket's getOutputStream method, then call the write method to write out, the data will be written out, and the other party will receive it if it calls the read method. Here we use the buffer stream BufferedWriter to write out. Then remember to call the flush method to brush out the contents of the cache. Finally, remember to close the stream, butYou cannot close directly, but instead call the shutdownOutput() method, which closes only the portion of the output without closing the socket.

* Close socket

The close method that calls socket s directly closes them.

Client

Create a socket

Create a locally identifiable socket that passes in the ip address and port number. You can then use the socket to receive and send data streams.

* Send data streams

Call getOutputStream() of socketThe method gets the output stream, then calls the write method to write out the data, and then another important step is to close the output stream to actually write out! But note that you can't call the close method of writer directly here, because this will close the socket directly and make it unusable later. Instead, flush out the buffer first.Go, then call the shutdownOutput() method to close the output stream so that the data is actually sent out.

The question here is: Why must the output stream be closed before data can be sent out!?

Incoming data streams

Call the socket's getInputStream() method to get the input stream, then call the read method to read the data in. Finally, call the shutdownInputStream() method to close the input stream.

* Close socket

The close method of the socket is last called to close the socket.

3. UDP Communication

Server Side

Create a socket

1. First create a socket as the local identity, which has a port number and an ip address (the operating system helps assign values). Packages sent using this socket carry the information of the socket, namely InetAddress and port.

Receive datagrams

2. Prepare a package to receive messages.

3. Then call the receive method of the socket to pass the package in, and the package will have the data. The package contains the data sent by the other party, the ip address of the other party and the corresponding port number.

* Send datagrams

4. Prepare a socket in which to place the data to be sent, the address to be sent, including the ip of the other party and its port number.

* Close socket

5. Close the socket at last

Client

Create a socket

1. Create a socket that belongs to the client and contains the port number and ip address through which all incoming and outgoing requests pass. The reason why ip needs to be specified here is because it is different from the server, where the server uses the system directly, and here it is specified, so they are different.

* Send datagrams

2. As with sending packets above, create a packet, and then have the data inside the package, the port number of the other party and the ip address of the other party.

3. Then call the send method to pass the package in

Receive datagrams

4. As above, you need to prepare a packet in advance and call the receive method

* Close socket

5. Close socket last

4. Differences between UDP and TCP

1. TCP is connection-oriented, UDP is connectionless, that is, do not shake hands beforehand. This causes TCP connections to need to create a "Welcome Socket" first. UDP is not used. That is, TCP connections need to create an additional serverSocket.

2. Establishing a connection over TCP requires a dedicated socket to mark the connection between the server and the client. UDP is not required. TCP requires a dedicated connection over the server socket. Socket socket = serverSocket.accept();

3. TCP sends and receives messages and sends and receives data streams. UDP sends and receives messages and sends and receives datagrams. The distinction between streams and reports requires a closer look at the article. Stream Stream uses sockets to get streams and send streams, xxx.read() reads in and xxx.write() writes out. And for operations that close streams, xx.shutIndownput()And xxx.shutdownOutput(). A report package is sent and received directly, socket.send(packet) and socket.receive (packet).

4. Do you need to set the difference between port number and ip address when sending out?

4.1 is not used when using TCP because the server-side connection information was set up when the Welcome Connection was created, and then the client-side connection information was set up at accept. Therefore, there is no need to specify where to send the stream.

4.2When you use UDP again, you know from the image that it's gone, then it's gone. That's the message I sent, and then it's gone. So when you send a datagram, you need to label where it's going, the ip address, and the port number there. Instead, TCP is not used, you can see from the image that a connection has been established, and then you can make this welcome connection.There is no need to specify a location where the exclusive connection on the basis of the connection has been sent all the time.

Is it messy or useful to keep it?

3. UDP

Introduction to 2.1 UDP

UDP is connectionless compared to TCP's connection-oriented, and connectionless refers to two ends (client and server in this case)This UDP is also an unreliable connection because it does not require a wave to connect directly before a connection is established. UDP, because it is disconnected, does not need to establish a socket connection to shake hands first, just like a TCP connection. UDP is directly connected between the client and server.

Therefore, the server side creates a socket directly, and then this socket is to guard a port on the server side waiting for the client's request, that is, using a socket on the server side, you can complete the connection with all clients, and use this socket to receive and send all requests.

2.2 Process

The code for this chapter is in socket_udp_001

Server Side

The first step is to write the server-side code. First, the server-side needs to create a socket that needs to pass in a portPort number parameter, so this socket represents the port number gate in this host for receiving and dispatching work on this port number on this host. Outgoing datagrams need to go through this socket, and incoming sockets also need to go through this socket.

DatagramSocket datagramSocket = new DatagramSocket(7799);
//Constructs a datagram socket and binds it to the specified port 
//on the local host machine. The socket will be bound to the wildcard 
//address, an IP address chosen by the kernel.

The second step is to prepare for receipt, that is, the client sends messages to this port of the server, which the socket receives and uses the pre-prepared packets to store the data.

Since UDP is the way a packet is sent and received, you need to prepare a packet to receive it. Then put the packet in the receive method, put the received data on the packet's cache when there is data to send, and then we can read the data in the packet we prepared in advance.That's OK. (Because the byte is cached, we need to convert it to a String.)

Also note that the data sent includes the ip address and port number of the sender, so this packet also includes the ip address and port number of the sender.

Then you need to be aware that this receive method is used to receive datagrams, which means that if no data is sent, the receive method will remain on standby and will block until the data is sent.

 //[2] Create packets designed to receive messages from clients
    byte[] content01 = new byte[1024];
    DatagramPacket packet01 = new DatagramPacket(content01, content01.length);
    Log.d(TAG, "run: wait for request......");
 //[3] The messages sent by the receiving client are all in this package 01
    datagramSocket.receive(packet01);//Blocked here
 //[3.1] Messages sent by clients are printed here
    String content_from_client = new String(content01, 0, packet01.getLength());
    Log.d(TAG, "run: Message from client----->" + content_from_client);

 //DatagramPacket(content01, content01.length)
 //Constructs a DatagramPacket for receiving packets of length length.
 //The length argument must be less than or equal to buf.length.

 //receive( )
 //Receives a datagram packet from this socket. When this method returns, the 
 //DatagramPacket's buffer is filled with the data received. The datagram packet also 
 //contains the sender's IP address, and the port number on the sender's machine.

The third step is to send messages to the client on the server side. Similarly, UDP-based messages are received and sent in the form of datagram packages, so it is natural to use packet packages to send messages here. However, note that the incoming parameters and the way in which the packets are constructed are different here, so they do not work the same.One is to receive and the other is to send.

Here you need to prepare a packet and put four things in it: the ip address of the other party, the port number of the other party, what to send, and the length of the packet. Then you call the send method of the socket to send the packet.

//[4] Messages to clients are also sent using a single packet (not as a stream)
   byte[] content02 = "Hello Client!".getBytes();
//[4.1] Here in this package, we're going to send the past ip and port numbers
   DatagramPacket packet02 = new DatagramPacket(content02, content02.length, packet01.getAddress(), packet01.getPort());
   Log.d(TAG, "run: Server ready to send message");
   datagramSocket.send(packet02);

//public DatagramPacket(byte[] buf,int length,java.net.InetAddress address,int port)
//Constructs a datagram packet for sending packets of length length to the specified port 
//number on the specified host. The length argument must be less than or equal to buf.length.

//send method
//Sends a datagram packet from this socket. The DatagramPacket includes information 
//indicating the data to be sent, its length, the IP address of the remote host, and the port 
//number on the remote host.

Step 4 is a very common step, and for security reasons, we need to close the socket. Of course, generally because we want to keep this socket on this server waiting for requests, we don't need to close it directly unless we don't want it to request.

Complete Code

The following is the complete code, and the changes above are threads and a while loop. Threads are network operations that necessarily require networking, so we need to open a thread to specifically handle these things. Then because we need to set up this server socket port, we need to be on standby all the time so that we don't have to open it again and again.This is to use a while loop to wait for the next loop response after each request response and send is processed.

package com.example.socket_udp_001;

import android.util.Log;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;


public class Server01 {

    private static final String TAG = "Server01";
    boolean flag = true;

    //Create a server-side listening port
    //Unlike TCP, datagram ports need to create a welcome port while creating a dedicated port.
    //The server side only needs one port to respond to all client requests
    public void createServerSocket() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //[1] Create a server-side packet socket to wait for client requests
                //     Guarded on port 7799, as long as another client sends a request to this port, it performs the action
                DatagramSocket datagramSocket = null;
                try {
                    datagramSocket = new DatagramSocket(7799);
                } catch (SocketException e) {
                    e.printStackTrace();
                }

                //The server only needs to be turned on once, and then it can always receive requests
                // Because UDP is disconnected, it is really necessary to create a package every time to receive the data sent.
                // They cannot be treated as the same connection, each is different, UDP is connectionless!
                while (flag) {
                    try {
                        //[2] Create packets designed to receive messages from clients
                        byte[] content01 = new byte[1024];
                        DatagramPacket packet01 = new DatagramPacket(content01, content01.length);
                        Log.d(TAG, "run: wait for request......");

                        //[3] The messages sent by the receiving client are all in this package 01
                        Log.d(TAG, "run: Ready to receive messages");
                        datagramSocket.receive(packet01);//Blocked here
                        //[3.1] Messages sent by clients are printed here
                        String content_from_client = new String(content01, 0, packet01.getLength());
                        Log.d(TAG, "run: Message from client----->" + content_from_client);

                        //[4] Messages to clients are also sent using a single packet (not as a stream)
                        byte[] content02 = "Hello Client!".getBytes();
                        //[4.1] Here in this package, we're going to send the past ip and port numbers
                        DatagramPacket packet02 = new DatagramPacket(content02, content02.length, packet01.getAddress(), packet01.getPort());
                        Log.d(TAG, "run: Server ready to send message");
                        datagramSocket.send(packet02);

                    } catch (SocketException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                //[5] Close the connection
                datagramSocket.close();
            }
        }).start();
    }
}

* Client

The client and the server are essentially the same, except that the client sends and receives first. The same is true, you need to create a socket local identity to receive and send using the socket. Note that the same is true, when sending out, you use a package to send and when receiving, you use a package to receive.

Because a socket has its own ip address and port number, when it is sent with this socket, the package actually carries the ip address and port number automatically. Then the same is true, because the ip address and port number are identified, they can correspond when someone sends them.

The complete code is as follows:

package com.example.socket_udp_001;

import android.util.Log;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class Client {

    private static final String TAG = "Client";

    //Client Interface
    public void createClientSocket(){
        new Thread(()->{
            try {
                //[1] Note that creating a client's port is a local identity
                int port = 7788;
                InetAddress addr = InetAddress.getByName("127.0.0.1");
                DatagramSocket datagramSocket = new DatagramSocket(port,addr);

                //[2] Create a packet to send data to the server
                byte[] content01 = "hello Server".getBytes();
                DatagramPacket packet01 = new DatagramPacket(content01,content01.length,addr,7799);
                Log.d(TAG, "createClientSocket: Preparing to send data to the server...");
                datagramSocket.send(packet01);//android.os.NetworkOnMainThreadException

                //[3] Create a packet to receive data from the server
                byte[] content02 = new byte[1024];
                DatagramPacket packet02 = new DatagramPacket(content02,content02.length);
                Log.d(TAG, "createClientSocket: Preparing to receive data from the server...");
                datagramSocket.receive(packet02);
                //Print out received data
                String content_from_server = new String(content02,0,packet02.getLength());
                Log.d(TAG, "createClientSocket:Data sent by the server----> "+content_from_server);

                //[4] Turn off socket s
                datagramSocket.close();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (SocketException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

Posted by slipmatt2002 on Tue, 21 Sep 2021 09:14:06 -0700