Java使用线程池实现socket编程的方法详解

Java使用线程池实现socket编程的方法详解

简介

Java中的线程池是用来管理和复用线程的工具。线程池可以减少线程的创建和销毁,节省了系统资源。在socket编程中,线程池可以避免创建大量的线程,优化程序性能。

线程池的实现

线程池的创建可以使用Java中的ExecutorExecutorService接口。这两个类都是Executor框架的一部分,提供了管理线程池和执行线程任务的方法。

下面是一个创建线程池的示例代码:

ExecutorService executor = Executors.newFixedThreadPool(10);

创建的是一个固定大小的线程池,大小为10。根据实际需求,也可以创建单线程池、缓存线程池和可变尺寸线程池。

socket编程与线程池的结合

下面是一个简单的socket编程示例,接收客户端请求并返回信息:

public class Server {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端启动完成,等待客户端请求...");
        while (true) {
            Socket socket = serverSocket.accept();
            System.out.println("接收到客户端请求:" + socket.getInetAddress().getHostAddress() + ":" + socket.getPort());
            InputStream inputStream = socket.getInputStream();
            byte[] buf = new byte[1024];
            int length = inputStream.read(buf);
            String request = new String(buf, 0, length);
            System.out.println("接收到客户端请求:" + request);
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write("Hello World!".getBytes());
            outputStream.flush();
            outputStream.close();
            inputStream.close();
            socket.close();
        }
    }
}

这是一个简单的服务端代码,使用ServerSocket监听端口8888,接收客户端请求并返回信息。

如果仅使用上面的代码,每当有一个客户端连接上来,就会创建一个新的线程来处理请求。如果客户端请求很频繁,就会导致线程创建和销毁的频繁操作,浪费系统资源。

使用线程池来优化代码,只需要将核心代码包装在Runnable接口中,提交给线程池执行即可,如下:

public class Server {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端启动完成,等待客户端请求...");
        ExecutorService executor = Executors.newFixedThreadPool(10);
        while (true) {
            Socket socket = serverSocket.accept();
            System.out.println("接收到客户端请求:" + socket.getInetAddress().getHostAddress() + ":" + socket.getPort());
            executor.submit(new Handler(socket));
        }
    }
}

class Handler implements Runnable {
    private Socket socket;

    public Handler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            InputStream inputStream = socket.getInputStream();
            byte[] buf = new byte[1024];
            int length = inputStream.read(buf);
            String request = new String(buf, 0, length);
            System.out.println("接收到客户端请求:" + request);
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write("Hello World!".getBytes());
            outputStream.flush();
            outputStream.close();
            inputStream.close();
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

上面的代码将核心代码封装到Handler类中,并且通过创建线程池的方式来使用线程池,对客户端请求进行处理。

多线程socket编程示例

下面是一个多线程socket编程的示例,客户端连接成功后,传输文件到服务端:

服务端代码:

public class Server {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端启动完成,等待客户端请求...");
        ExecutorService executor = Executors.newFixedThreadPool(10);
        while (true) {
            Socket socket = serverSocket.accept();
            System.out.println("接收到客户端请求:" + socket.getInetAddress().getHostAddress() + ":" + socket.getPort());
            executor.submit(new Handler(socket));
        }
    }
}

class Handler implements Runnable {
    private Socket socket;

    public Handler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            InputStream inputStream = socket.getInputStream();
            byte[] buf = new byte[1024];
            int length = inputStream.read(buf);
            String request = new String(buf, 0, length);
            if (request.equalsIgnoreCase("file")) {
                System.out.println("请求传输文件");
                length = inputStream.read(buf);
                String fileName = new String(buf, 0, length);
                System.out.println("文件名:" + fileName);
                OutputStream outputStream = new FileOutputStream(fileName);
                while ((length = inputStream.read(buf)) != -1) {
                    outputStream.write(buf, 0, length);
                }
                System.out.println("传输完成");
                outputStream.close();
            } else {
                System.out.println("接收到客户端请求:" + request);
                OutputStream outputStream = socket.getOutputStream();
                outputStream.write("Hello World!".getBytes());
                outputStream.flush();
                outputStream.close();
            }
            inputStream.close();
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

客户端代码:

public class Client {
    public static void main(String[] args) throws Exception {
        Socket socket = new Socket("localhost", 8888);
        OutputStream outputStream = socket.getOutputStream();
        Scanner scanner = new Scanner(System.in);
        System.out.println("输入文件名发送文件,否则发送字符串");
        String input = scanner.nextLine();
        if (isFile(input)) {
            outputStream.write("file".getBytes());
            outputStream.flush();
            outputStream.write(input.getBytes());
            outputStream.flush();
            InputStream inputStream = new FileInputStream(input);
            byte[] buf = new byte[1024];
            int length;
            while ((length = inputStream.read(buf)) != -1) {
                outputStream.write(buf, 0, length);
            }
            inputStream.close();
            outputStream.flush();
            outputStream.close();
        } else {
            outputStream.write(input.getBytes());
            outputStream.flush();
            InputStream inputStream = socket.getInputStream();
            byte[] buf = new byte[1024];
            int length = inputStream.read(buf);
            String response = new String(buf, 0, length);
            System.out.println(response);
            inputStream.close();
            outputStream.close();
        }
        socket.close();
    }

    private static boolean isFile(String input) {
        try {
            File file = new File(input);
            if (file.isFile()) {
                return true;
            }
            return false;
        } catch (Exception e) {
            return false;
        }
    }
}

上面的代码中,如果客户端输入的是文件名,则客户端向服务端发送"file"请求,并传输文件到服务端;否则客户端向服务端发送普通字符串请求,服务端返回"Hello World!"。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java使用线程池实现socket编程的方法详解 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • C++ 超详细梳理继承的概念与使用

    C++ 超详细梳理继承的概念与使用 概念 继承是一种面向对象程序设计中的重要概念,指的是一个类从另一个类获得其成员变量和成员函数的能力。 基类:具有被继承的成员函数和成员变量的类,也称为父类。 派生类:继承了基类属性的类,也称为子类。在派生类中可以定义新的成员函数和成员变量,也可以重载或覆盖基类的成员函数和成员变量。 继承方式分为公有继承、私有继承和保护继承…

    C 2023年5月22日
    00
  • 逍遥自在学C语言 | 赋值运算符

    前言 在C语言中,赋值运算符用于将一个值赋给变量 这个过程分为两个步骤: 计算赋值运算符右侧的表达式 将结果赋给左侧的变量。 C语言提供了多个不同的赋值运算符,包括基本的赋值运算符、复合赋值运算符以及条件赋值运算符等 一、人物简介 第一位闪亮登场,有请今后会一直教我们C语言的老师 —— 自在。 第二位上场的是和我们一起学习的小白程序猿 —— 逍遥。 二、基本…

    C 2023年4月25日
    00
  • 一文教你Qt如何操作SQLite数据库

    一文教你Qt如何操作SQLite数据库 1. 安装SQLite数据库驱动 在Qt中操作SQLite数据库,需要使用到SQLite数据库驱动。下面介绍如何安装和配置这个驱动。 1.1 下载SQLite 访问 SQLite官网 ,选择最新的预编译二进制文件下载。 1.2 下载SQLite驱动 访问Qt官网的下载页面,选择对应版本的Qt安装程序。这里以Qt 5.1…

    C 2023年5月22日
    00
  • 如何在 C++ 中实现一个单例类模板

    当我们在开发一个项目时,有时需要一个只能被实例化一次的类,这种情况下就需要使用单例模式。C++中实现单例模式可以通过单例类模板来实现。 下面详细讲解如何在C++中实现一个单例类模板: 1. 定义单例类 template<typename T> class Singleton { public: static T& instance() {…

    C 2023年5月23日
    00
  • CCleaner怎么关闭自动更新?CCleaner关闭自动更新方法

    当你安装CCleaner之后,它默认会启用自动更新功能,这意味着即使你不手动检查更新,它也会在后台自动下载并安装新版本的CCleaner。对于一些用户来说,这可能不是一个理想的操作行为。那么,如何关闭CCleaner自动更新呢?下面是详细的步骤。 方法一:通过CCleaner程序关闭自动更新 打开CCleaner程序,点击左下角的“选项”按钮。 切换到“设置…

    C 2023年5月23日
    00
  • 详解C++编程中断言static_assert的使用

    详解C++编程中断言static_assert的使用 在C++中,当我们需要在编译期进行类型检查或常量计算时,可以使用static_assert。具体来说,static_assert是一个语言特性,用于在编译期进行断言判断,如果判断条件为false,则程序会在编译期抛出一个编译错误,阻止程序的继续编译。 用法 static_assert可以用于两种类型的判断…

    C 2023年5月23日
    00
  • win7系统开机搜狗应用程序错误(0xc0000409)导致电脑死机

    问题描述 有用户反馈在使用 Win7 系统开机时,出现搜狗应用程序错误(0xc0000409)导致电脑死机的问题。为了解决这个问题,下面是一个完整攻略。 步骤一:删除搜狗输入法 由于问题是由搜狗应用程序引起的,我们可以尝试卸载搜狗输入法以解决问题。具体步骤如下: 点击桌面左下角 Windows 图标,打开“控制面板”。 在“控制面板”页面中,选择“程序”。 …

    C 2023年5月23日
    00
  • Java日常练习题,每天进步一点点(43)

    以下是Java日常练习题43的完整攻略。 题目描述 本题目要求实现一个方法,该方法接受一个整数数组,返回数组中最大的两个数之和。 方法签名 public static int maxTwoSum(int[] nums) 示例输入输出 示例1: 输入: [1,2,3,4,5] 输出: 9 示例2: 输入: [7,5,1,6,3,0] 输出: 13 解题思路 这…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部