黑马全套Java教程(九):网络编程(四)

简介: 黑马全套Java教程(九):网络编程

黑马全套Java教程(九):网络编程(三)+https://developer.aliyun.com/article/1556507

37.4 线程池优化

ServerDemo2.java

package d8_socket4;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;
//目标:实现服务端可以同时处理多个客户端的消息
public class ServerDemo2 {
    //使用静态变量记住一个线程池对象
    private static ExecutorService pool = new ThreadPoolExecutor(3,5,6,
            TimeUnit.SECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
    public static void main(String[] args) {
        try {
            System.out.println("=====服务端启动成功=====");
            //1. 注册端口
            ServerSocket serverSocket = new ServerSocket(6666);
            //定义一个死循环由主线程负责不断的接收客户端的Socket管道连接
            while (true) {
                //2. 每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取消息
                Socket socket = serverSocket.accept();
                System.out.println(socket.getRemoteSocketAddress() + ":它来了,上线了!");
                //任务对象负责读取消息
                Runnable target = new ServerReaderRunnable(socket);
                pool.execute(target);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ClientDemo1.java

package d8_socket4;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
//目标:使用线程池优化,实现通信
public class ClientDemo1 {
    public static void main(String[] args) {
        try {
            System.out.println("=====客户端启动成功=====");
            //1. 创建Socket通信管道请求有服务端的连接
            //public Socket(String host, int port)
            //参数一:服务器的IP
            //参数二:服务端的端口
            Socket socket = new Socket("127.0.0.1",6666);
            //2. 从socket通信管道中得到一个字节输出流,负责发送数据
            OutputStream os = socket.getOutputStream();
            //3. 把低级的字节流包装成打印流
            PrintStream ps = new PrintStream(os);
            Scanner sc = new Scanner(System.in);
            while (true) {
                //4. 发送消息
                System.out.println("请说:");
                String msg = sc.nextLine();
                ps.println(msg);
                ps.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ServerReaderRunnable.java

package d8_socket4;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
public class ServerReaderRunnable implements Runnable{
    private Socket socket;
    public ServerReaderRunnable(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run(){
        try {
            //3. 从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4. 把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5. 按照行读取消息
            String msg;
            while((msg = br.readLine()) != null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (IOException e) {
            System.out.println(socket.getRemoteSocketAddress() + ":下线了!");
        }
    }
}


案例:即时通信

即时通信的含义,要怎么设计:

  • 即时通信,是指一个客户端的消息发出去,其他客户端可以接收到
  • 即时通信需要进行端口转发的设计思想
  • 服务端需要把在线的Socket管道存储起来
  • 一旦收到一个消息要推送给其他管道

ServerReaderThread.java

package d9_tcp_sms;
import d8_socket4.ServerReaderRunnable;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
//目标:实现服务端可以同时处理多个客户端的消息
public class ServerDemo2 {
    //定义一个静态的List集合存储当前全部在线的socket管道
    public static List<Socket> allOnlineSockets = new ArrayList<>();
    public static void main(String[] args) throws Exception{
        System.out.println("=====服务端启动成功=====");
        //1. 注册端口
        ServerSocket serverSocket = new ServerSocket(6666);
        //定义一个死循环由主线程负责不断的接收客户端的Socket管道连接
        while (true) {
            //2. 每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取消息
            Socket socket = serverSocket.accept();
            System.out.println(socket.getRemoteSocketAddress() + ":上线了!");
            //任务对象负责读取消息
            Runnable target = new ServerReaderRunnable(socket);
            allOnlineSockets.add(socket);   //上线完成
            //3. 创建一个独立的线程来单独处理这个socket管道
            new ServerReaderThread(socket).start();
        }
    }
}
class ServerReaderThread extends Thread {
    private Socket socket;
    public ServerReaderThread(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            //3. 从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4. 把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5. 按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null) {
                System.out.println(socket.getRemoteSocketAddress() + "发来了:" + msg);
                //把这个消息进行端口转发给全部客户端socket管道
                sendMsgToAll(msg);
            }
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + ":下线了!");
            ServerDemo2.allOnlineSockets.remove(socket);
        }
    }
    private void sendMsgToAll(String msg) throws Exception{
        for(Socket socket : ServerDemo2.allOnlineSockets){
            PrintStream ps = new PrintStream(socket.getOutputStream());
            ps.println(msg);
            ps.flush();
        }
    }
}

ClientDemo1.java

package d9_tcp_sms;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        System.out.println("=====客户端启动成功=====");
        //1. 创建Socket通信管道请求有服务端的连接
        Socket socket = new Socket("127.0.0.1", 6666);
        //创建一个独立的线程专门负责这个客户端的读消息(服务端随时可能转发消息过来)
        new ClientReaderThread(socket).start();
        //2. 从socket通信管道中得到一个字节输出流,负责发送数据
        OutputStream os = socket.getOutputStream();
        //3. 把低级的字节流包装成打印流
        PrintStream ps = new PrintStream(os);
        //4. 发送消息
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请说:");
            String msg = sc.nextLine();
            ps.println(msg);
            ps.flush();
        }
    }
}
class ClientReaderThread extends Thread {
    private Socket socket;
    public ClientReaderThread(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            //3. 从socket通信管道中得到一个字节输入流
            InputStream is = socket.getInputStream();
            //4. 把字节输入流包装成缓冲字符输入流进行消息的接收
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //5. 按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null) {
                System.out.println("收到消息:" + msg);
            }
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + ":服务端把你踢出去了!");
        }
    }
}


案例:模拟BS系统

package d10_bs;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;
//目标:实现服务端可以同时处理多个客户端的消息
public class BSserverDemo {
    public static void main(String[] args) throws Exception{
        //1. 注册端口
        ServerSocket serverSocket = new ServerSocket(8080);
        //2. 创建一个循环接收多个客户端的请求
        while (true) {
            Socket socket = serverSocket.accept();
            //3. 创建一个独立的线程来单独处理这个socket管道
            new ServerReaderThread(socket).start();
        }
    }
}
class ServerReaderThread extends Thread {
    private Socket socket;
    public ServerReaderThread(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            //浏览器  已经与本线程建立了Socket管道
            //响应消息给浏览器显示
            PrintStream ps = new PrintStream(socket.getOutputStream());
            //必须响应HTTP协议格式数据,否则浏览器不认识消息
            ps.println("HTTP/1.1 200 OK");  //协议类型和版本  响应成功的消息!
            ps.println("Content-Type:text/html;charset=UTF-8");  //响应的数据类型:文本/网页
            ps.println();  //必须发送一个空行
            //才可以响应数据回去给浏览器
            ps.println("<span style='color:red;font-size:90px'>《Java大法好》 </span>");
            ps.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

例2:利用线程池优化

package d10_bs;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;
//目标:实现服务端可以同时处理多个客户端的消息
public class BSserverDemo {
    //使用静态变量记住一个线程池对象
    private static ExecutorService pool = new ThreadPoolExecutor(3,5,6,
            TimeUnit.SECONDS, new ArrayBlockingQueue<>(2),
            Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
    public static void main(String[] args) throws Exception{
        //1. 注册端口
        ServerSocket serverSocket = new ServerSocket(8080);
        //2. 创建一个循环接收多个客户端的请求
        while (true) {
            Socket socket = serverSocket.accept();
            //3. 创建一个独立的线程来单独处理这个socket管道
            pool.execute(new ServerReaderThread(socket));
        }
    }
}
class ServerReaderThread extends Thread {
    private Socket socket;
    public ServerReaderThread(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            //浏览器  已经与本线程建立了Socket管道
            //响应消息给浏览器显示
            PrintStream ps = new PrintStream(socket.getOutputStream());
            //必须响应HTTP协议格式数据,否则浏览器不认识消息
            ps.println("HTTP/1.1 200 OK");  //协议类型和版本  响应成功的消息!
            ps.println("Content-Type:text/html;charset=UTF-8");  //响应的数据类型:文本/网页
            ps.println();  //必须发送一个空行
            //才可以响应数据回去给浏览器
            ps.println("<span style='color:red;font-size:90px'>《Java大法好》 </span>");
            ps.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
目录
相关文章
|
3月前
|
安全 网络协议 算法
Nmap网络扫描工具详细使用教程
Nmap 是一款强大的网络发现与安全审计工具,具备主机发现、端口扫描、服务识别、操作系统检测及脚本扩展等功能。它支持多种扫描技术,如 SYN 扫描、ARP 扫描和全端口扫描,并可通过内置脚本(NSE)进行漏洞检测与服务深度枚举。Nmap 还提供防火墙规避与流量伪装能力,适用于网络管理、渗透测试和安全研究。
537 1
|
4月前
|
JSON 移动开发 网络协议
Java网络编程:Socket通信与HTTP客户端
本文全面讲解Java网络编程,涵盖TCP与UDP协议区别、Socket编程、HTTP客户端开发及实战案例,助你掌握实时通信、文件传输、聊天应用等场景,附性能优化与面试高频问题解析。
|
4月前
|
Java 关系型数据库 数据库
Java 项目实战教程从基础到进阶实战案例分析详解
本文介绍了多个Java项目实战案例,涵盖企业级管理系统、电商平台、在线书店及新手小项目,结合Spring Boot、Spring Cloud、MyBatis等主流技术,通过实际应用场景帮助开发者掌握Java项目开发的核心技能,适合从基础到进阶的学习与实践。
570 3
|
2月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
193 1
|
2月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
215 1
|
3月前
|
安全 Java
Java之泛型使用教程
Java之泛型使用教程
281 10
|
2月前
|
Oracle Java 关系型数据库
Java 简单教程
Java是跨平台、面向对象的编程语言,广泛用于企业开发、Android应用等。本教程涵盖环境搭建、基础语法、流程控制、面向对象、集合与异常处理,助你快速入门并编写简单程序,为进一步深入学习打下坚实基础。
338 0
|
2月前
|
机器学习/深度学习 分布式计算 Java
Java与图神经网络:构建企业级知识图谱与智能推理系统
图神经网络(GNN)作为处理非欧几里得数据的前沿技术,正成为企业知识管理和智能推理的核心引擎。本文深入探讨如何在Java生态中构建基于GNN的知识图谱系统,涵盖从图数据建模、GNN模型集成、分布式图计算到实时推理的全流程。通过具体的代码实现和架构设计,展示如何将先进的图神经网络技术融入传统Java企业应用,为构建下一代智能决策系统提供完整解决方案。
363 0
|
5月前
|
缓存 安全 Java
Java 并发新特性实战教程之核心特性详解与项目实战
本教程深入解析Java 8至Java 19并发编程新特性,涵盖CompletableFuture异步编程、StampedLock读写锁、Flow API响应式流、VarHandle内存访问及结构化并发等核心技术。结合电商订单处理、缓存系统、实时数据流、高性能计数器与用户资料聚合等实战案例,帮助开发者高效构建高并发、低延迟、易维护的Java应用。适合中高级Java开发者提升并发编程能力。
165 0
|
安全 Java Linux
(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!
IO(Input/Output)方面的基本知识,相信大家都不陌生,毕竟这也是在学习编程基础时就已经接触过的内容,但最初的IO教学大多数是停留在最基本的BIO,而并未对于NIO、AIO、多路复用等的高级内容进行详细讲述,但这些却是大部分高性能技术的底层核心,因此本文则准备围绕着IO知识进行展开。
535 1

热门文章

最新文章