廖雪峰Java13网络编程-1Socket编程-3TCP多线程编程

TCP多线程编程
一个ServerSocket可以和多个客户端同时建立连接,所以一个Server可以同时与多个客户端建立好的Socket进行双向通信。
因此服务器端,当我们打开一个Socket以后,通常使用一个无限for循环,在这个for循环内部,每次调用accept方法,返回一个与远程客户新建的Socket连接,紧接着启动一个新的线程,来处理这个连接。

    ServerSocket ss = new ServerSocket(port);
    for( ; ; ){
        Socket sock = ss.accept();
        Thread t = new Thread(){
            public void run(){
                process(sock);
            }
        }
        t.start();
    }

TCPServer.java

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;

public class TCPServer {
    public static void main(String[] args) throws Exception{
        ServerSocket ss = new ServerSocket(9090);
        System.out.println("TCP Server ready");
        for(;;){
            Socket sock = ss.accept();
            System.out.println("Accept from "+sock.getRemoteSocketAddress());
            TimeHandle handle = new TimeHandle(sock);
            handle.start();
        }
    }
}
class TimeHandle extends Thread{
    Socket sock;
    TimeHandle(Socket sock){
        this.sock = sock;
    }
    public void run(){
        try(BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream(), StandardCharsets.UTF_8))){
            try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream(),StandardCharsets.UTF_8))){
                for(;;){
                    String cmd = reader.readLine();
                    if("q".equals(cmd)){
                        writer.write("bye!\n");
                        writer.flush();
                        break;
                    }else if("time".equals(cmd)){
                        writer.write(LocalDateTime.now().toString()+"\n");
                        writer.flush();
                    }else{
                        writer.write("Sorry?\n");
                        writer.flush();
                    }
                }
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            try{
                this.sock.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}

运行2次client,服务器端的运行结果

TCPClient.java

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class TCPClient {
    public static void main(String[] args) throws Exception{
        InetAddress addr = InetAddress.getByName("localhost");
        System.out.println(addr);
        try(Socket sock = new Socket(addr,9090)){
            try(BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream(), StandardCharsets.UTF_8))){
                try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream(),StandardCharsets.UTF_8))){
                    writer.write("time\n");
                    writer.flush();
                    String resp = reader.readLine();
                    System.out.println("Response:"+resp);
                    Thread.sleep(1000);
                    writer.write("q\n");
                    writer.flush();
                    resp=reader.readLine();
                    System.out.println("Response:"+resp);
                }
            }
        }
    }
}

总结:

TCP多线程编程模型:

  • 服务器端使用无限循环
  • 每次accept返回后,创建新的线程来处理客户端请求
  • 每个客户端请求对应一个服务线程
  • 使用线程池可以提高运行效率
posted on 2019-07-07 12:44  singleSpace  阅读(156)  评论(0编辑  收藏  举报