Java NIO中涉及的基础内容:

  • Channel 通道
  • Buffer 缓冲区
  • File IO 文件IO
  • Network IO 网络IO

最简单的基于Socket的服务端多线程模型,服务器为每一个客户端派发一个线程,新的线程只负责单独的客户端数据。为了接受客户端连接,服务端会有一个单独的派发线程。

package testnio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 多线程的Java TCP服务示例
 */
public class MultiThreadEchoServer {
    //可缓存线程池 用来处理每一个客户端
    private static ExecutorService tp = Executors.newCachedThreadPool();

    /**
     * 内部类,负责创建线程并处理socket数据
     */
    static class HandleMsg implements Runnable{

        //读取Socket内容并返回
        Socket serverSocket;
        public HandleMsg(Socket serverSocket){
            this.serverSocket = serverSocket;
        }

        @Override
        public void run() {
            BufferedReader inStream = null;
            PrintWriter outStream = null;

            try {
                inStream = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
                outStream = new PrintWriter(serverSocket.getOutputStream(), true);
                String inputLine = null;
                //处理客户端请求
                long b = System.currentTimeMillis();
                while ((inputLine = inStream.readLine()) != null){
                    outStream.println(inputLine);
                }
                long e = System.currentTimeMillis();
                System.out.println("spend:" + (e-b)+"ms");

            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    if (inStream != null) inStream.close();
                    if (outStream != null) outStream.close();
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

    }

    /**
     * 入口方法,根据连接创建新的处理线程和服务端Socket来处理业务
     * @param args
     */
    public static void main(String[] args) {
        ServerSocket echoServer = null;
        Socket serverSocket = null;

        try {
            echoServer = new ServerSocket(8001);
        } catch (IOException e) {
            e.printStackTrace();
        }

        while (true){
            try {
                //accept()方法会一致阻塞在这里,直到新的客户端连接到来
                serverSocket = echoServer.accept();
                System.out.println(serverSocket.getRemoteSocketAddress() + " connect!");
                tp.execute(new HandleMsg(serverSocket));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }


}

最简单的测试Java TCP客户端

package testnio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;

/**
 * 简单的IO阻塞方式客户端
 */
public class EchoClient {
    public static void main(String[] args) throws IOException {
        Socket client = null;
        PrintWriter writer = null;
        BufferedReader reader = null;

        client = new Socket();
        try {
            client.connect(new InetSocketAddress("localhost", 8001));
            writer = new PrintWriter(client.getOutputStream(), true);
//            writer.println("Hello!");
            writer.println("I am client: " + client.getPort());

            writer.flush();

            reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
            System.out.println("from server: " + reader.readLine());

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) writer.close();
            if (reader != null) reader.close();

            client.close();
        }


    }
}

这种处理方式有一个严重问题,如果客户端处理比较慢每一个线程中都会阻塞操作,CPU会等待网络IO,如果有大量并发请求,这种方式实极其不合理的。

Tags: Java, 网络编程, NIO

Related Posts:

Leave a Comment