9.2.2Socket(TCP)

一.过程:

1.建立连接(不是握手),虽然内核中的连接有很多,但是在应用程序中,要一个一个处理.

  1. 获取任务:使用ServerSocket.accept()方法,作用是把内核中的连接获取到应用程序中,这个过程类似于生产者消费者模型.
  1. 使用缓冲的时候,注意全缓冲和行缓冲.

4.注意关闭文件资源(client.socket.close()).

二.问题处理:

解决方法:使用多线程.

2.C10M问题:并发量太大.

解决方案:开源节流.

开源:创建线程.

节流:I/O多路复用,I/O多路转接.(java NIO)

三.代码实现:

1.回显服务器:

java 复制代码
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class EchoTcpServer {

    private ServerSocket serverSocket = null;
    private ExecutorService service = Executors.newCachedThreadPool();

    // 手动设置端口号
    public EchoTcpServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }

    // 启动服务器
    public void start() throws IOException {
        System.out.println("服务器启动");
        while (true) {
            Socket clientSocket = serverSocket.accept();
//             processConnection(clientSocket);

//            Thread thread = new Thread(() -> {
//                try {
//                    processConnection(clientSocket);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            });
//            thread.start();

            service.submit(() -> {
                try {
                    processConnection(clientSocket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }

    // 处理一个连接
    private void processConnection(Socket clientSocket) throws IOException {
        System.out.println("[" + clientSocket.getInetAddress().toString() + " " + clientSocket.getPort() + "]客户端已上线");
        // 接下来进行读取请求,计算响应,返回响应三步走策略
        try (InputStream inputStream = clientSocket.getInputStream();
             OutputStream outputStream = clientSocket.getOutputStream()) {
            Scanner scanner = new Scanner(inputStream);
            // 一次连接可能会伴随多次请求与回应
            while (true) {
                // 1.读取请求
                if (!scanner.hasNext()) {
                    // 读取结束
                    System.out.println("[" + clientSocket.getInetAddress().toString() + " " + clientSocket.getPort() + "]客户端已下线");
                    return;
                }
                // Tcp的数据是以字节流的形式发送的,这里默认发送文本文件.
                String request = scanner.next();
                // 2.处理请求
                String response = process(request);
                // 3.返回结果
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(response);
                // 刷新
                printWriter.flush();
                System.out.println("[" + clientSocket.getInetAddress().toString() + " " + clientSocket.getPort() + "] 接收: "
                + request + " 回复:" + response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭文件
            clientSocket.close();
        }
    }

    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        EchoTcpServer server = new EchoTcpServer(1999);
        server.start();
    }
}

2.回显用户端:

java 复制代码
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class EchoTcpClient {

    private Socket socket = null;

    public EchoTcpClient(String serverIp, int serverPort) throws IOException {
        // 完成建立连接
        socket = new Socket(serverIp, serverPort);
    }

    public void start() {
        System.out.println("客户端起动");
        Scanner scannerConsole = new Scanner(System.in);

        try (InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream()) {
            while (true) {
                // 输入请求
                System.out.println("->");
                String request = scannerConsole.next();
                // 发送请求
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(request);
                printWriter.flush();
                // 接收响应
                Scanner scannerNetwork = new Scanner(inputStream);
                String response = scannerNetwork.next();
                // 打印响应
                System.out.println(response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) throws IOException {
        EchoTcpClient client = new EchoTcpClient("127.0.0.1", 1999);
        client.start();
    }
}

3.字典服务器:

java 复制代码
import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;

public class DictionaryTcpServer extends EchoTcpServer{

    private Map<String, String> dictionary = new HashMap<>();

    public DictionaryTcpServer(int port) throws IOException {
        super(port);
        dictionary.put("I", "我");
        dictionary.put("love", "爱");
        dictionary.put("China", "中国");
    }

    @Override
    public String process(String request) {
       return dictionary.getOrDefault(request, "没找到");
    }

    public static void main(String[] args) throws IOException {
        EchoTcpServer server = new DictionaryTcpServer(1999);
        server.start();
    }
}
相关推荐
2501_922895585 分钟前
基于SpringBoot和Leaflet集成在线天气服务的区县当前天气WebGIS实战
java·spring boot·后端
苹果醋36 分钟前
[MySQL] MySQL 版本不支持 ST_Distance_Sphere替代方案和解决方案
java·运维·spring boot·mysql·nginx
天天摸鱼的java工程师18 分钟前
Spring事务什么时候会失效?常见业务场景详解与修复方案
java·后端·面试
打野二师兄43 分钟前
Spring Boot 自动配置:从 2.x 到 3.x 的进化之路
java·spring boot·后端
Monkey-旭1 小时前
Android JNI 语法全解析:从基础到实战
android·java·c++·c·jni·native
魑魅魍魉都是鬼2 小时前
随缘玩 一: 代理模式
android·java·代理模式
你我约定有三2 小时前
分布式微服务--RPC:原理、使用方式、与 HTTP/REST 的区别与选择
java·开发语言·分布式·后端·微服务·rpc
loop lee2 小时前
【JVM】常见的 Java 垃圾回收算法以及常见的垃圾回收器介绍及选型
java·jvm·算法
RainbowSea2 小时前
伙伴匹配系统(移动端 H5 网站(APP 风格)基于Spring Boot 后端 + Vue3 - 02
java·vue.js·spring boot
工业互联网专业2 小时前
基于JavaWeb的兼职发布平台的设计与实现
java·vue.js·spring boot·毕业设计·源码·课程设计·兼职发布平台