TCP communication - open multi-threaded server and read () causes the server to blocking problems

TCP communication file uploading Case


  • Local streams: client and server and the local hard disk read and write, you need to create your own stream of bytes

  • Network Flow: read and write between the client and server must use the byte stream objects provided Socket

Client work: read local files, uploaded to the server, the server reads the write-back of data


  • Clear data source
  • Destination: server

  • Client code:
package cn.learn.web;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class client {
    public static void main(String[] args) throws IOException {
        //创建一个本地的字节输入流,构造方法绑定数据源
        FileInputStream fileIn = new FileInputStream("b.txt");


        //*****发送数据******
        //创建客户端对象Socket,构造方法绑定服务器IP地址和端口号
        Socket socket = new Socket("127.0.0.1", 8020);
        //使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象
        OutputStream socketOut = socket.getOutputStream();


        //读入内存
        int len = 0;
        byte[] bytes = new byte[1024];
        //使用流中的write方法给服务器发送数据
        while ((len = fileIn.read(bytes)) != -1) {
            socketOut.write(bytes, 0, len);
        }


        //已上传完文件,但read()导致服务器阻塞,给服务器写一个结束标记
        socket.shutdownOutput();
        
        //使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象
        InputStream clientIn = socket.getInputStream();
        //使用InputStream对象中的read()方法,读取服务器回写的数据
        while ((len = clientIn.read(bytes)) != -1) {
            //打印看看
            System.out.println(new String(bytes, 0, len));
        }
        
        
        
        //释放资源,只关闭Socket的IO流就行
        fileIn.close();
        socket.close();

    }
}

Server: the client reads the file uploaded, saved to the server's hard to write client-side back "uploaded successfully"


  • clear:
    1. Data source: the client to upload files
    2. Destination: the server's hard disk d: \\ upload.txt

  • Server code:
package cn.learn.web;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws IOException {

        //设置通信端口号,不然系统随机分配
        ServerSocket server = new ServerSocket(8020);

        //使用serverSocket对象中的方法accept,获取到请求的客户端对象Socket(含地址和端口号)
        Socket socket1 = server.accept();

        //使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象
        InputStream serveIn = socket1.getInputStream();


        //判断文件夹是否存在,若不存在新建
        File file = new File("d:\\upload");
        if(!file.exists()){
            file.mkdir();
        }

        //创建服务器的本地字节输出流,构造方法绑定输出位置,注意****\\******
        FileOutputStream localOut = new FileOutputStream(file+"\\b.txt");

        //获取读取的数据有效长度,循环读取和写入服务器硬盘
        byte[] bytes = new byte[1024];
        int len = 0;
        //使用serveIn的方法read,读取客户端发送的数据
        while ((len = serveIn.read(bytes)) != -1) {
            localOut.write(bytes,0,len);
            //打印到控制台看看
            System.out.println(new String(bytes, 0, len));

        }

        //使用Socket对象中的方法getOutputStream()获取网络字节输入流OutputStream对象
        OutputStream serverOut = socket1.getOutputStream();

        //6.使用serverOut中的write方法回写给客户端
        serverOut.write("我收到了,上传成功".getBytes());

        //7.释放socket1与server的流
        server.close();
        socket1.close();
    }
}

Note: The server has been turned on, wait for the client to upload


  • After the completion of TCP communication server has not reason to stop

    1. read () method, if no input is available, method blocks
    2. Specific reasons are read with a read cycle (), read no end tag, the server has been waiting to enter the blocked state

// done uploading files, but read () result in obstruction to the server to write a closing tag
socket.shutdownOutput ();

The code optimization


  • Optimize server storage file name

        /*
        自定义服务器本地存储文件名称,防止冲突覆盖
        规则:域名+毫秒值+随机数
         */
        String filename = "learn" + System.currentTimeMillis()+ (new Random().nextInt(10)+1)+".txt";

        //创建服务器的本地字节输出流,构造方法绑定输出位置,注意****\\******
        FileOutputStream localOut = new FileOutputStream(file+"\\"+filename);
  • The server has been in a listening state, circulating accept accepted socket operation (instead of blocking), and finally without shutting down the server

  • Used in a loop multi-threading, improve efficiency, there is a client upload file, it opens a thread. Copy code block to the run () method, using try catch attention thrown

Server code optimization, multi-threaded open

package cn.learn.web;


import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;


public class Server {
    public static void main(String[] args) throws IOException {

        //设置通信端口号,不然系统随机分配
        ServerSocket server = new ServerSocket(8020);

        /*
        循环,使得服务器一直处于监听状态,有客户端上传文件,就存入
         */
        while (true) {

            //使用serverSocket对象中的方法accept,获取到请求的客户端对象Socket(含地址和端口号)
            Socket socket1 = server.accept();

            /******
             客户端每上传一个文件,就开启一个多线程
             ******/
            new Thread(new Runnable() {

                @Override
                public void run() {
                    try {
                        //使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象
                        InputStream serveIn = socket1.getInputStream();


                        //判断文件夹是否存在,若不存在新建
                        File file = new File("d:\\upload");
                        if (!file.exists()) {
                            file.mkdir();
                        }

                        /*
                        自定义服务器本地存储文件名称,防止冲突覆盖
                        规则:域名+毫秒值+随机数
                        */
                        String filename = "learn" + System.currentTimeMillis() + (new Random().nextInt(10) + 1) + ".txt";

                        //创建服务器的本地字节输出流,构造方法绑定输出位置,注意****\\******
                        FileOutputStream localOut = new FileOutputStream(file + "\\" + filename);

                        //获取读取的数据有效长度,循环读取和写入服务器硬盘
                        byte[] bytes = new byte[1024];
                        int len = 0;
                        //使用serveIn的方法read,读取客户端发送的数据
                        while ((len = serveIn.read(bytes)) != -1) {
                            localOut.write(bytes, 0, len);
                        }


                        //使用Socket对象中的方法getOutputStream()获取网络字节输入流OutputStream对象
                        OutputStream serverOut = socket1.getOutputStream();

                        //6.使用serverOut中的write方法回写给客户端
                        serverOut.write("我收到了,上传成功".getBytes());

                        //7.释放socket1与server的流
                        socket1.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

Guess you like

Origin www.cnblogs.com/huxiaobai/p/11614101.html