On the optimization of socket file transfer rate

Keywords: TCP/IP

preface

Recently, there is a need to improve the transmission speed of the transfer file of the replacement assistant. Let's see what a change assistant is first.


Generally, the replacement assistants of manufacturers look like this, that is, they copy some data from the old mobile phone to the new mobile phone. Data generally include: contacts, SMS, wallpaper, pictures, music, video, files, settings, etc. Then, the files are transmitted through the socket protocol after the wifi or wifi direct connection is used. This article focuses on how to improve the transmission speed of socket. Here are some concepts:

1.wifi and WiFi P2P (direct connection)

Wi Fi direct is a new technology that enables point-to-point Wi Fi connections between devices such as smartphones and digital cameras, even in environments without traditional Wi Fi networks or Wi Fi access points.

P2P is the abbreviation of English Peer-to-Peer, also known as "Peer-to-Peer". "Peer-to-Peer" technology is a new network technology, which depends on the computing power and bandwidth of participants in the network, rather than concentrating the dependencies on a few servers. P2P is also the abbreviation of Point to Point in English. If you know about miracast, you should also know this.

Wi Fi is a technology that can connect personal computers, handheld devices (such as PDA, mobile phone) and other terminals to each other wirelessly. Wi Fi is a brand of wireless network communication technology, which is owned by the Wi Fi alliance.

2. Transmission scheme used by the replacement assistant

Generally speaking, there are two schemes for transferring files between old and new mobile phones in the market:

  1. Using the original socket scheme, the old mobile phone sends data as the client and the new mobile phone receives data as the server

  2. The new mobile phone creates a hotspot. After the old mobile phone is connected, a server environment is created, and then the new mobile phone downloads the files of the old mobile phone through the url through the HTTP client

No matter which of the above two is used, one mobile phone needs to open the hotspot and the other to connect, and the above schemes are finally transmitted using the socket protocol.

1. Mental process of rate optimization

After getting the optimization requirements, I always feel that there is not much room for optimization at the upper level. Because our current average transmission speed is 6M/s, while Huawei's maximum transmission speed can reach 70M/S. Huawei must have optimized the bottom layer of socket protocol. Then I put our apk on Huawei mobile phones, and the speed did not improve significantly. This shows that the cause is still implemented in the upper layer. At this time, many years of debug ging experience tells me that this problem may only be solved by opening more threads in the end. But I'm still too young.

2. Summary

1. Give priority to 5G network

Generally speaking, after a wifi is connected, you can see this in the wifi details. The transmission link speed is basically the maximum speed of the wifi. Divided by 8, it is the maximum upload and download speed. What we see now is 86Mbps, so if you use this network to transfer files, it will be 10M/s at most. This is a hard condition. However, the transmission link speed will also change in real time, so we will see that our transmission speed will also change continuously, but the basic change is small.

If 5G hotspots are used here, the transmission link speed above can reach more than 300Mbps. Therefore, the transmission speed will also change qualitatively. The following is the core of creating 5G wifi p2p

  boolean supportWifi5G = mWifiManager.is5GHzBandSupported();
 //First, you need to judge whether the mobile phone supports 5G
​    try {
​      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && supportWifi5G) {
​        Reflect.invokeMethod(manager, "setWifiP2pChannels", channel, 0, 48, null);
​      } else {
​        Reflect.invokeMethod(manager, "setWifiP2pChannels", channel, 0, 6, null);
​      }
//Before setting wifi, you must set a channel for wifi. As for what is a channel, you can check it online. At that time, 5G wifi was not created successfully because the 48 channel was not set for 5G (of course, more than 48 channels are valid). 
    
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && supportWifi5G) {
​      WifiP2pConfig.Builder builder = new WifiP2pConfig.Builder().setNetworkName("DIRECT-")
​          .setPassphrase("987654321").setGroupOperatingBand(GROUP_OWNER_BAND_5GHZ);
​      manager.createGroup(channel, builder.build(), listener);
​    } else {
​      manager.createGroup(channel, listener);
    }
    // Then set the account and password. The account must start with DIRECT, otherwise an error will be reported.

https://blog.csdn.net/qq_43804080/article/details/103390070 WIFI 2.4G and 5G channel division table (with wireless communication frequency allocation table)

2. Consider using thread pool to maximize performance

At first, when 5g WiFi was not used, I tried to use thread pool to optimize the speed, but it was found that it didn't work. However, after upgrading 5g WiFi, I found a problem that the transmission speed would drop when transmitting some small and many files, such as transmitting more than 1000 pictures. This is because the speed available now is large, but each time a small file is transmitted, the rest of the speed will be wasted. Therefore, after 5g WiFi is used, the thread pool is used to transfer multiple pictures at the same time when small and many files are added synchronously. In this way, the speed will be greatly improved.

3. Adjust the size of cache bytes

Let's take a simple example of sending and receiving files.

 private void sendFile(String path, String FileName) {
        DhcpInfo info = wifiManager.getDhcpInfo();
        String serverAddress = WIFIAdmin.intToIp(info.serverAddress);

        try {
            Socket s = new Socket();
            s.connect(new InetSocketAddress(serverAddress, PORT), 3000);
            OutputStream out = s.getOutputStream();
            //Write the file name at the head of the stream to # split
            out.write((FileName + "#").getBytes());
            File file = new File(path);
            long length = file.length() / 1024 / 1024;
            String str = "Client information:" + s.getLocalAddress() + " P:" + s.getLocalPort() +
                    " \n Server information:" + s.getInetAddress() + " P:" + s.getPort() +
                    "\nserverAddress:" + serverAddress +
                    "\n File:" + path +
                    "\n Transfer file size:" + length + "M";
            Message message = new Message();
            message.obj = str.toString();
            handler.sendMessage(message);
            FileInputStream inputStream = new FileInputStream(file);
            byte[] buf = new byte[1024];
            // You can modify the buffer size here. There is also an increase in speed.
            int len;
            //Determine whether to read to the end of the file
            while ((len = inputStream.read(buf)) != -1) {
                out.write(buf, 0, len);
                Log.d("xiechangtao", "send:len:" + len);
                calculateSpeed(len);
                //Writes the file loop to the output stream
            }
            //Tell the server that the file has been transferred
            s.shutdownOutput();
            //Get feedback from the server
            BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
            String serverBack = in.readLine();
            Log.d("TAG", serverBack);
            //Resource shutdown
            s.close();
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

``

private void receiveFile() {
    try {
        int num = 0;
        ServerSocket ss = new ServerSocket(WIFIAdmin.PORT);
        while (true) {
            num++;
            Socket socket = ss.accept();
            tv_server_info.setText("There are new client connections:" +"num:"+ socket.getInetAddress() +
                    " P:" + socket.getPort());

            InputStream in = socket.getInputStream();
            int content;
            //Load an array of file names
            byte[] c = new byte[1024];  
            //Resolve the file name in the stream, that is, the first stream
            for (int i = 0; (content = in.read()) != -1; i++) {
                //Indicates that the file name has been read
                if (content == '#') {
                    break;
                }
                c[i] = (byte) content;
            }
            //Convert byte [] into characters, that is, the file name we need
            String FileName = new String(c, "utf-8").trim();
            //Create a file, specify the save path and the file name just transferred
            OutputStream saveFile = new FileOutputStream(new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), FileName));
            byte[] buf = new byte[1024]; // Modify buffer size here
            int len;
            //Determine whether to read to the end of the file
            final long startTime = System.currentTimeMillis();
            while ((len = in.read(buf)) != -1) {
                saveFile.write(buf, 0, len);
                calculateSpeed(len);
            }
            saveFile.flush();
            saveFile.close();
            //Tell the sender that I have received it
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write("File received successfully".getBytes());
            final long endTime = System.currentTimeMillis();
            final long costTime = endTime - startTime;
            Message message = new Message();
            message.obj = "The transfer was completed and took a total of:" + costTime / 1000 + "S";
            handler.sendMessage(message);
            outputStream.flush();
            outputStream.close();
            socket.close();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
4. Use socket api

The following are some socket API s. It is said on the Internet that they can improve the speed, but I have tried, which is useless. But put it here together.

// Whether to turn on the Nagle algorithm? It is said that the speed can be doubled when it is turned off, but I have hardly found any change
socket.setTcpNoDelay(true);

// Set receive transmit buffer size
socket.setReceiveBufferSize(64 * 1024 * 1024);
socket.setSendBufferSize(64 * 1024 * 1024);

// Set performance parameters: relative importance of short link, delay and bandwidth
socket.setPerformancePreferences(1, 1, 0);

setTrafficClass(int trafficClass)
1) IP Four service types are specified to qualitatively describe the service quality:
l Low cost: low sending cost.
l High reliability: ensure the reliable delivery of data to the destination.
l Maximum throughput: a large number of data can be received or sent at one time.
l Minimum delay: the speed of transmitting data is fast, and the data can be delivered to the destination quickly.
2) These four service types can also be combined. For example, high reliability and minimum delay can be required at the same time. Socket Class provides methods for setting and reading service types:
l Set service type: public void setTrafficClass(int trafficClass) throws SocketException
l Read service type: public int getTrafficClass() throws SocketException
3) Socket Class represents the service type with four integers:
l Low cost: 0 x02 ((the penultimate bit of binary is 1)
l High reliability: 0 x04(The penultimate bit of binary is 1)
l Maximum throughput: 0 x08(The penultimate bit of binary is 1)
l Minimum delay: 0 x10(The penultimate bit of binary is 1)

Other commonly used API s are attached here

//Whether to send confirmation data (similar to heartbeat packet) when there is no data response for a long time. The time is about 2 hours
socket.setKeepAlive(true);

//How to handle the close operation behavior; The default is false, 0
//false, 0: by default, it returns immediately when it is closed. The underlying system takes over the output stream and sends the data in the buffer
//true, 0: return immediately when closing, discard the buffer data, and directly send the RST end command to the other party without 2MSL waiting
//true, 200: the maximum blocking time is 200ms when closing, and then it will be handled as the second case
socket.setSoLinger(true, 20);

//Whether to make emergency data introverted. The default is false; Emergency data through socket.sendUrgentData(1); send out
socket.setOOBInline(true);

//Set the read timeout to 2 seconds

socket.setSoTimeout(2000);

//Whether to reuse the Socket address that is not completely closed is valid for the Socket after the specified bind operation
socket.setReuseAddress(true);

Big summary

To sum up, if you want to improve the transmission speed of socket, you should first use 5G wifi, and then use thread pool and transmission buffer size to improve the speed.

Posted by marijn on Thu, 30 Sep 2021 17:26:48 -0700