当前位置: 首页 > news >正文

Java入门级教程22——Socket编程

目录

1.实现基础“一问一答”式通信

2.实现连续多次通信

3.应用多线程处理多个客户端连接

4.引用线程池处理多线程并发

5.引用自定义线程池


1.实现基础“一问一答”式通信

基础的TCP/IP Socket 编程的例子,实现一个简单的 “一问一答” 式的通信。服务器启动后等待客户端连接,客户端连接后发送一条消息,服务器接收后再回复一条消息。

① Server1.java (服务器端)

package com.hy.chapter1;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.Scanner;// 服务器端Socket
// 通过ServerSocket对客户机请求的监听
public class Server1 {// 声明ServerSocket,它是服务器的“总机”,负责监听端口和接受连接private ServerSocket serverSocket;public void startServer() {System.out.println("Socket服务器启动,正在监听端口 8891...");try {// 1. 创建ServerSocket实例,并绑定到8891端口serverSocket = new ServerSocket(8891);// 2. 调用accept()方法,等待客户端连接Socket socket = serverSocket.accept();System.out.println("服务器有客户机建立了连接,客户端地址: " + socket.getInetAddress());// 3. 获取输入流,用于读取客户端发送的数据BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));// 4. 读取客户端发送的一行数据String msg = br.readLine();System.out.println("服务器接受到的客户机的消息为:" + msg);// 5. 服务器准备回复消息System.out.println("请服务器构建消息....");Scanner scanner = new Scanner(System.in);String str = scanner.next(); // 6. 获取输出流,用于向客户端发送数据PrintWriter pw = new PrintWriter(socket.getOutputStream());// 7. 发送数据//    println() 会自动在字符串末尾添加换行符,这与客户端的readLine()相对应pw.println(str);// 8. 刷新输出流//    强制将缓冲区中的数据立即发送出去,否则客户端可能收不到消息pw.flush();} catch (IOException e) {System.err.println("服务器发生IO异常: " + e.getMessage());e.printStackTrace();} finally {if (serverSocket != null) {try {serverSocket.close();System.out.println("服务器Socket已关闭。");} catch (IOException e) {e.printStackTrace();}}}}public static void main(String[] args) {Server1 server1 = new Server1();server1.startServer();}
}

② Client1.java (客户端)

package com.hy.chapter1;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;public class Client1 {// 声明Socket,它是客户端与服务器通信的端点private Socket socket;public void startClient() {System.out.println("客户机正在启动,尝试连接服务器...");try {// 1. 创建Socket实例,指定要连接的服务器IP和端口socket = new Socket("127.0.0.1", 8891);System.out.println("客户机和服务器连接成功!");// 2. 准备要发送给服务器的消息System.out.println("请求客户机构建消息:");Scanner scanner = new Scanner(System.in);String str = scanner.next();// 3. 获取输出流,向服务器发送数据PrintWriter pw = new PrintWriter(socket.getOutputStream());// 4. 发送数据,并自动添加换行符pw.println(str);// 5. 刷新流,确保数据被立即发送pw.flush();// 6. 获取输入流,等待接收服务器的回复BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));// 7. 读取服务器回复的一行数据(此方法会阻塞)String msg = br.readLine();System.out.println("客户机接受到的服务器的消息为:" + msg);} catch (UnknownHostException e) {System.err.println("无法识别服务器主机: " + e.getMessage());e.printStackTrace();} catch (IOException e) {System.err.println("客户端发生IO异常: " + e.getMessage());e.printStackTrace();} finally {if (socket != null) {try {socket.close();System.out.println("客户端Socket已关闭。");} catch (IOException e) {e.printStackTrace();}}}}public static void main(String[] args) {Client1 c = new Client1();c.startClient();}
}

输出结果:

服务器:

Socket服务器启动,正在监听端口 8891...
服务器有客户机建立了连接,客户端地址: /127.0.0.1
服务器接受到的客户机的消息为:你好服务机
请服务器构建消息....
你好客户机
服务器Socket已关闭。

客户机:

客户机正在启动,尝试连接服务器...
客户机和服务器连接成功!
请求客户机构建消息:
你好服务机
客户机接受到的服务器的消息为:你好客户机
客户端Socket已关闭。

2.实现连续多次通信

过在服务器端和客户端都加入了 while(true) 无限循环,实现了多次通信的功能。

① Server1.java (服务器端)

package com.hy.chapter2;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.Scanner;// 服务器端Socket
// 通过ServerSocket对客户机请求的监听
public class Server1 {// 声明ServerSocket,它是服务器的“总机”private ServerSocket serverSocket;public void startServer() {System.out.println("Socket服务器启动,正在监听端口 8891...");try {serverSocket = new ServerSocket(8891);// 关键改进:使用 while(true) 循环,使服务器可以接受多个客户端的连接while(true) {// 1. 接受客户端连接 (阻塞方法)Socket socket = serverSocket.accept();System.out.println("服务器与一个新客户机建立了连接: " + socket.getInetAddress());// 2. 获取输入流,读取客户端发送的一条消息BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String msg = br.readLine(); // 阻塞,直到读取到一行数据System.out.println("服务器接受到的客户机的消息为:" + msg);// 3. 从服务器控制台读取回复消息System.out.println("请服务器构建消息....");Scanner scanner = new Scanner(System.in);String str = scanner.next();// 4. 获取输出流,将回复消息发送给客户端PrintWriter pw = new PrintWriter(socket.getOutputStream());pw.println(str); // 发送数据并换行pw.flush(); // 强制发送// 5. 关闭与当前客户端的连接资源socket.close();System.out.println("与该客户机的通信结束,连接已关闭。");}} catch (IOException e) {System.err.println("服务器发生IO异常: " + e.getMessage());e.printStackTrace();}}public static void main(String[] args) {Server1 server1 = new Server1();server1.startServer();}
}

② Client1.java (客户端)

package com.hy.chapter2;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;public class Client1 {// 声明Socketprivate Socket socket;public void startClient() {System.out.println("客户机启动,进入通信循环...");// 关键改进:使用 while(true) 循环,使客户端可以发送多条消息while (true){try {// 1. 每次循环都创建一个新的Socket连接到服务器socket = new Socket("127.0.0.1", 8891);System.out.println("客户机和服务器连接成功");// 2. 从客户端控制台读取要发送的消息System.out.println("请输入要发送给服务器的消息 (输入 'exit' 退出):");Scanner scanner = new Scanner(System.in);String str = scanner.next();// 退出逻辑if ("exit".equals(str)) {System.out.println("客户端主动退出。");break; // 跳出while循环}// 3. 获取输出流,发送消息PrintWriter pw = new PrintWriter(socket.getOutputStream());pw.println(str);pw.flush();// 4. 获取输入流,等待并接收服务器的回复 (阻塞方法)BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String msg = br.readLine();System.out.println("客户机接受到的服务器的消息为:" + msg);} catch (UnknownHostException e) {System.err.println("无法识别服务器主机: " + e.getMessage());e.printStackTrace();} catch (IOException e) {System.err.println("与服务器通信失败,请检查服务器是否开启。");e.printStackTrace();break;} finally {if (socket != null && !socket.isClosed()) {try {socket.close();System.out.println("客户端Socket已关闭,准备下一次连接。\n");} catch (IOException e) {e.printStackTrace();}}}}}public static void main(String[] args) {Client1 c = new Client1();c.startClient();}
}

输出结果:

服务器:

Socket服务器启动,正在监听端口 8891...
服务器与一个新客户机建立了连接: /127.0.0.1
服务器接受到的客户机的消息为:服务机你好
请服务器构建消息....
客户机你好
与该客户机的通信结束,连接已关闭。
服务器与一个新客户机建立了连接: /127.0.0.1
服务器接受到的客户机的消息为:向服务机再次发送消息
请服务器构建消息....
接受到消息
与该客户机的通信结束,连接已关闭。
服务器与一个新客户机建立了连接: /127.0.0.1
服务器接受到的客户机的消息为:null
请服务器构建消息....

客户机:

客户机启动,进入通信循环...
客户机和服务器连接成功
请输入要发送给服务器的消息 (输入 'exit' 退出):
服务机你好
客户机接受到的服务器的消息为:客户机你好
客户端Socket已关闭,准备下一次连接。

客户机和服务器连接成功
请输入要发送给服务器的消息 (输入 'exit' 退出):
向服务机再次发送消息
客户机接受到的服务器的消息为:接受到消息
客户端Socket已关闭,准备下一次连接。

客户机和服务器连接成功
请输入要发送给服务器的消息 (输入 'exit' 退出):
exit
客户端主动退出。
客户端Socket已关闭,准备下一次连接。

3.应用多线程处理多个客户端连接

将多线程引入服务器端,解决单线程服务器只能 “一次服务一个客户” 的致命缺陷,创建同时处理多个客户端连接的能力。

① Server1.java (服务器端)

package com.hy.chapter3;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;// 服务器端Socket
// 通过ServerSocket对客户机请求的监听
public class Server1 {// 声明ServerSocketprivate ServerSocket serverSocket;public void startServer() {System.out.println("Socket服务器启动,正在监听端口 8891...");try {serverSocket = new ServerSocket(8891);// 无限循环,不断接受新的客户端连接while (true) {// 1. 接受客户端连接 (阻塞方法)Socket socket = serverSocket.accept();// 2. 连接成功后,打印当前处理线程的名字System.out.println("服务器有客户机建立了连接,主处理线程: " + Thread.currentThread().getName());// 3. 创建一个新的线程来处理这个连接new SocketThread(socket).start(); // 4. 主线程立即返回while循环的开头,继续调用accept()等待下一个客户端}} catch (IOException e) {System.err.println("服务器发生IO异常: " + e.getMessage());e.printStackTrace();}}public static void main(String[] args) {Server1 server1 = new Server1();server1.startServer();}
}

② SocketThread.java (线程处理类)

package com.hy.chapter3;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Random;// 这个类负责处理单个客户端的通信
public class SocketThread extends Thread {// 每个线程都持有一个与特定客户端关联的Socket对象Socket socket;// 构造函数,用于接收主服务器传递过来的Socketpublic SocketThread(Socket socket) {this.socket = socket;}// 线程的入口方法,当调用start()时,此方法会被执行public void run() {try (BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter pw = new PrintWriter(socket.getOutputStream(), true)) { // true表示自动刷新// 1. 读取客户端发送的消息 (阻塞方法)String msg = br.readLine();// 打印当前工作线程的名字和接收到的消息,以证明是多线程在工作System.out.println(Thread.currentThread().getName() + " 服务器接受到的客户机的消息为:" + msg);// 2. 模拟服务器处理业务逻辑System.out.println(Thread.currentThread().getName() + " 正在处理请求...");Thread.sleep(20 * 1000); // 故意让线程休眠20秒// 3. 构建并发送回复消息给客户端String response = "你好,客户端!这是你的随机数字: " + new Random().nextInt(1000);pw.println(response);// 因为PrintWriter构造时传入了true,所以这里不需要手动调用pw.flush()System.out.println(Thread.currentThread().getName() + " 已向客户端发送回复,任务完成。");} catch (IOException e) {System.err.println(Thread.currentThread().getName() + " 与客户端通信时发生IO异常: " + e.getMessage());e.printStackTrace();} catch (InterruptedException e) {System.err.println(Thread.currentThread().getName() + " 线程被中断: " + e.getMessage());e.printStackTrace();}}
}

③ Client1.java (客户端)

package com.hy.chapter3;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;public class Client1 {private Socket socket;public void startClient() {System.out.println("客户机正在启动...");Scanner scanner = new Scanner(System.in); while (true){try {// 1. 创建Socket连接到服务器socket = new Socket("127.0.0.1", 8891);System.out.println("客户机和服务器连接成功");// 2. 从键盘读取要发送的消息System.out.println("请输入要发送给服务器的消息 (输入 'exit' 退出):");String str = scanner.next();if ("exit".equals(str)) {System.out.println("客户端主动退出。");break;}// 3. 发送消息PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);pw.println(str);// 4. 接收服务器回复 (阻塞方法)BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String msg = br.readLine();System.out.println("客户机接受到的服务器的消息为:" + msg);} catch (IOException e) {System.err.println("与服务器通信失败,请检查服务器是否开启。");e.printStackTrace();break;} finally {if (socket != null && !socket.isClosed()) {try {socket.close();System.out.println("客户端Socket已关闭。\n");} catch (IOException e) {e.printStackTrace();}}}}scanner.close(); }public static void main(String[] args) {Client1 c = new Client1();c.startClient();}
}

输出结果:

服务器:

Socket服务器启动,正在监听端口 8891...
服务器有客户机建立了连接,主处理线程: main
Thread-0 服务器接受到的客户机的消息为:111
Thread-0 正在处理请求...
Thread-0 已向客户端发送回复,任务完成。
服务器有客户机建立了连接,主处理线程: main
Thread-1 服务器接受到的客户机的消息为:222
Thread-1 正在处理请求...
服务器有客户机建立了连接,主处理线程: main
Thread-2 服务器接受到的客户机的消息为:333
Thread-2 正在处理请求...
Thread-1 已向客户端发送回复,任务完成。
服务器有客户机建立了连接,主处理线程: main
Thread-2 已向客户端发送回复,任务完成。
服务器有客户机建立了连接,主处理线程: main

客户机1:

客户机正在启动...
客户机和服务器连接成功
请输入要发送给服务器的消息 (输入 'exit' 退出):
111
客户机接受到的服务器的消息为:你好,客户端!这是你的随机数字: 713
客户端Socket已关闭。

客户机和服务器连接成功
请输入要发送给服务器的消息 (输入 'exit' 退出):
222
客户机接受到的服务器的消息为:你好,客户端!这是你的随机数字: 703
客户端Socket已关闭。

客户机和服务器连接成功
请输入要发送给服务器的消息 (输入 'exit' 退出):

客户机2:

客户机正在启动...
客户机和服务器连接成功
请输入要发送给服务器的消息 (输入 'exit' 退出):
333
客户机接受到的服务器的消息为:你好,客户端!这是你的随机数字: 421
客户端Socket已关闭。

客户机和服务器连接成功
请输入要发送给服务器的消息 (输入 'exit' 退出):

4.引用线程池处理多线程并发

引入了线程池(ThreadPool),这是构建高并发、高可用网络服务器的关键一步。它解决了多线程服务器中可能出现的 “线程爆炸” 问题,极大地提升了服务器的性能和稳定性。

① Server1.java (服务器端)

package com.hy.chapter4;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;// 服务器端Socket
// 通过ServerSocket对客户机请求的监听
public class Server1 {// 声明ServerSocketprivate ServerSocket serverSocket;public void startServer() {System.out.println("Socket服务器启动,正在监听端口 8891...");try {serverSocket = new ServerSocket(8891);// 【核心改进】创建一个线程池// Executors.newFixedThreadPool(2) 创建一个固定大小的线程池,池中最多同时有2个线程。ExecutorService espool = Executors.newFixedThreadPool(2);while (true) {// 1. 接受客户端连接 (阻塞方法)Socket socket = serverSocket.accept();// 打印当前主线程的名字System.out.println("服务器有客户机建立了连接,主处理线程: " + Thread.currentThread().getName());// 2. 将处理任务提交给线程池//    execute() 会将这个 SocketThread 任务放入线程池的任务队列中。//    如果线程池中有空闲线程,会立即执行这个任务。//    如果所有线程都在忙碌,这个任务会排队等待,直到有线程空闲。espool.execute(new SocketThread(socket));}} catch (IOException e) {System.err.println("服务器发生IO异常: " + e.getMessage());e.printStackTrace();}}public static void main(String[] args) {Server1 server1 = new Server1();server1.startServer();}
}

② SocketThread.java (线程处理类)

package com.hy.chapter4;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Random;// 这个类定义了与单个客户端通信的任务
public class SocketThread extends Thread {Socket socket;public SocketThread(Socket socket) {this.socket = socket;}// 线程的入口方法,当线程池中的线程执行此任务时,run()方法会被调用public void run() {try (BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter pw = new PrintWriter(socket.getOutputStream(), true)) { // true表示自动刷新// 1. 读取客户端消息String msg = br.readLine();// 打印执行此任务的线程名System.out.println(Thread.currentThread().getName() + " 服务器接受到的客户机的消息为:" + msg);// 2. 模拟耗时的业务处理System.out.println(Thread.currentThread().getName() + " 正在处理请求...");Thread.sleep(20 * 1000); // 模拟耗时操作// 3. 发送回复pw.println("你好,客户端!这是你的随机数字: " + new Random().nextInt(1000));System.out.println(Thread.currentThread().getName() + " 已向客户端发送回复,任务完成。");} catch (IOException e) {System.err.println(Thread.currentThread().getName() + " 与客户端通信时发生IO异常: " + e.getMessage());e.printStackTrace();} catch (InterruptedException e) {System.err.println(Thread.currentThread().getName() + " 线程被中断: " + e.getMessage());e.printStackTrace();}}
}

③ Client1.java (客户端)

package com.hy.chapter4;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;public class Client1 {private Socket socket;public void startClient() {System.out.println("客户机正在启动...");Scanner scanner = new Scanner(System.in); while (true){try {// 1. 创建Socket连接到服务器socket = new Socket("127.0.0.1", 8891);System.out.println("客户机和服务器连接成功");// 2. 从键盘读取要发送的消息System.out.println("请输入要发送给服务器的消息 (输入 'exit' 退出):");String str = scanner.next();if ("exit".equals(str)) {System.out.println("客户端主动退出。");break;}// 3. 发送消息PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);pw.println(str);// 4. 接收服务器回复 (阻塞方法)BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String msg = br.readLine();System.out.println("客户机接受到的服务器的消息为:" + msg);} catch (IOException e) {System.err.println("与服务器通信失败,请检查服务器是否开启。");e.printStackTrace();break;} finally {if (socket != null && !socket.isClosed()) {try {socket.close();System.out.println("客户端Socket已关闭。\n");} catch (IOException e) {e.printStackTrace();}}}}scanner.close(); }public static void main(String[] args) {Client1 c = new Client1();c.startClient();}
}

输出结果:

服务器:

Socket服务器启动,正在监听端口 8891...
服务器有客户机建立了连接,主处理线程: main
服务器有客户机建立了连接,主处理线程: main
服务器有客户机建立了连接,主处理线程: main
pool-1-thread-1 服务器接受到的客户机的消息为:111
pool-1-thread-1 正在处理请求...
pool-1-thread-2 服务器接受到的客户机的消息为:222
pool-1-thread-2 正在处理请求...
pool-1-thread-1 已向客户端发送回复,任务完成。
pool-1-thread-1 服务器接受到的客户机的消息为:333
pool-1-thread-1 正在处理请求...
服务器有客户机建立了连接,主处理线程: main
pool-1-thread-2 已向客户端发送回复,任务完成。
服务器有客户机建立了连接,主处理线程: main
pool-1-thread-1 已向客户端发送回复,任务完成。
服务器有客户机建立了连接,主处理线程: main

客户机1:

客户机正在启动...
客户机和服务器连接成功
请输入要发送给服务器的消息 (输入 'exit' 退出):
111
客户机接受到的服务器的消息为:你好,客户端!这是你的随机数字: 871
客户端Socket已关闭。

客户机和服务器连接成功
请输入要发送给服务器的消息 (输入 'exit' 退出):

客户机2:

客户机正在启动...
客户机和服务器连接成功
请输入要发送给服务器的消息 (输入 'exit' 退出):
222
客户机接受到的服务器的消息为:你好,客户端!这是你的随机数字: 993
客户端Socket已关闭。

客户机和服务器连接成功
请输入要发送给服务器的消息 (输入 'exit' 退出):

客户机3:

客户机正在启动...
客户机和服务器连接成功
请输入要发送给服务器的消息 (输入 'exit' 退出):
333
客户机接受到的服务器的消息为:你好,客户端!这是你的随机数字: 245
客户端Socket已关闭。

客户机和服务器连接成功
请输入要发送给服务器的消息 (输入 'exit' 退出):

5.引用自定义线程池

ThreadPool.java (核心:线程池管理器)WorkThread.java (工作线程)Server1.java (服务器端 - 使用自定义线程池)

① 定义任务单元 (SocketThread.java)

package com.hy.chapter6;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Random;// 定义任务单元
public class SocketThread extends Thread {// 每个任务都必须持有一个与特定客户端连接的Socket对象Socket socket;// 构造函数,用于接收服务器传递过来的Socket连接public SocketThread(Socket socket) {this.socket = socket;}// 实现任务的执行逻辑public void run() {try {BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String msg = br.readLine();System.out.println(Thread.currentThread().getName() + "服务器接受到的客户机的消息为:" + msg);System.out.println("请服务器构建消息....");Thread.sleep(20 * 1000);PrintWriter pw = new PrintWriter(socket.getOutputStream());// pw.write(str+"\n");pw.println("你好," + new Random().nextInt(1000));pw.flush();} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}}

② 实现工作线程 (WorkThread.java)

package com.hy.chapter6;public class WorkThread extends Thread {// 关联的线程池private ThreadPool threadPool;// 线程状态标记:是否空闲private boolean isIdle;public WorkThread(ThreadPool threadPool) {this.threadPool = threadPool;this.isIdle = true;}@Overridepublic void run() {System.out.println(this.getName() + " 启动,等待任务...");while (!isInterrupted()) { // 线程未被中断时持续运行try {// 从线程池获取任务(阻塞方法)Runnable task = threadPool.getTask();isIdle = false; // 标记为忙碌状态System.out.println(this.getName() + " 开始执行任务");task.run(); // 执行任务System.out.println(this.getName() + " 任务执行完成");isIdle = true; // 标记为空闲状态} catch (InterruptedException e) {System.out.println(this.getName() + " 被中断");break;}}System.out.println(this.getName() + " 退出");}public boolean isIdle() {return isIdle;}
}

③ 实现线程池管理器 (ThreadPool.java)

package com.hy.chapter6;import java.util.Vector;public class ThreadPool {// 线程池中的线程数量private int num;// 存储工作线程的集合(Vector线程安全)private Vector<WorkThread> threads;// 任务队列private Vector<Runnable> taskQueue;// 构造方法:初始化线程池,创建指定数量的工作线程public ThreadPool(int num) {this.num = num;this.threads = new Vector<>(num);this.taskQueue = new Vector<>();System.out.println("初始化线程池,核心线程数: " + num);// 创建并启动工作线程for (int i = 0; i < num; i++) {WorkThread worker = new WorkThread(this);threads.add(worker);worker.setName("工作线程-" + i);worker.start();}}// 提交任务到线程池public synchronized void execute(Runnable task) {// 添加任务到队列taskQueue.add(task);System.out.println("任务已加入队列,当前队列大小: " + taskQueue.size());// 唤醒等待的工作线程notify();}// 获取下一个任务(供工作线程调用)// synchronized 保证了在多线程环境下对任务队列的安全访问public synchronized Runnable getTask() throws InterruptedException {// 队列空时等待while (taskQueue.isEmpty()) {wait();}// 取出队列首个任务return taskQueue.remove(0);}public int getNum() {return num;}
}

④ 实现服务器主线程 (Server1.java)

package com.hy.chapter6;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.Random;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;// 服务器端Socket
// 通过ServerSocket对客户机请求的监听
public class Server1 {// 声明ServerSocketprivate ServerSocket serverSocket;public void startServer() {System.out.println("Socket服务器启动");try {serverSocket = new ServerSocket(8891);// 线程对象的复用// ExecutorService espool = Executors.newFixedThreadPool(2);ThreadPool thpool = new ThreadPool(2);while (true) {// 接受客户端连接 (阻塞方法)Socket socket = serverSocket.accept();System.out.println("服务器有客户机建立了连接," + Thread.currentThread().getName());// 创建任务,并提交给自定义的线程池thpool.execute(new SocketThread(socket));}} catch (IOException e) {e.printStackTrace();} finally {try {if (serverSocket != null) serverSocket.close();} catch (IOException e) {e.printStackTrace();}}}public static void main(String[] args) {Server1 server1 = new Server1();server1.startServer();}}

⑤ 实现客户端用于测试 (Client1.java)

package com.hy.chapter6;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;public class Client1 {private Socket socket;public void startClient() {System.out.println("客户机正在启动...");while (true) {try {socket = new Socket("127.0.0.1", 8891);System.out.println("客户机和服务器连接成功");System.out.println("请求客户机构建消息");Scanner scanner = new Scanner(System.in);String str = scanner.next();// 向服务器发送消息PrintWriter pw = new PrintWriter(socket.getOutputStream());// pw.write(str + "\r\n");pw.println(str);pw.flush();// 接收服务器响应BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String msg = br.readLine();System.out.println("客户机接受到的服务器的消息为:" + msg);} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {// 每次通信后关闭连接try {if (socket != null && !socket.isClosed()) {socket.close();}} catch (IOException e) {e.printStackTrace();}}// 短暂延迟,避免控制台输出混乱try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {Client1 c = new Client1();c.startClient();}}

输出结果:

服务器:

Socket服务器启动
初始化线程池,核心线程数: 2
工作线程-0 启动,等待任务...
工作线程-1 启动,等待任务...
服务器有客户机建立了连接,main
任务已加入队列,当前队列大小: 1
工作线程-0 开始执行任务
服务器有客户机建立了连接,main
任务已加入队列,当前队列大小: 1
工作线程-1 开始执行任务
工作线程-0服务器接受到的客户机的消息为:111
请服务器构建消息....
工作线程-1服务器接受到的客户机的消息为:222
请服务器构建消息....
工作线程-0 任务执行完成
服务器有客户机建立了连接,main
任务已加入队列,当前队列大小: 1
工作线程-0 开始执行任务
工作线程-1 任务执行完成
服务器有客户机建立了连接,main
任务已加入队列,当前队列大小: 1
工作线程-1 开始执行任务

客户机1:

客户机正在启动...
客户机和服务器连接成功
请求客户机构建消息
111
客户机接受到的服务器的消息为:你好,961
客户机和服务器连接成功
请求客户机构建消息

客户机2:

客户机正在启动...
客户机和服务器连接成功
请求客户机构建消息
222
客户机接受到的服务器的消息为:你好,285
客户机和服务器连接成功
请求客户机构建消息

http://www.dtcms.com/a/470228.html

相关文章:

  • 【Linux系统编程】2. Linux基本指令(上)
  • 网站系统介绍如何设置wordpress的内存
  • 毕业设计做网站做不出网站建设手机端pc端分开
  • Git删除本地与远程tag操作指南
  • 爱网站推广优化wordpress第三方登录教程
  • 23种设计模式——享元模式(Flyweight Pattern)
  • 游戏编程模式-享元模式(Flyweight)
  • 新郑做网站优化桂林网站优化公司
  • B站排名优化:知识、娱乐、生活类内容的差异化实操策略
  • 闵行网站制作设计公司昆明哪些做网站建设的公司
  • Spring Boot 3.x核心特性与性能优化实战
  • 域名解析后多久打开网站建个人网站
  • 基于MATLAB的PIV(粒子图像测速) 实现方案
  • 北京市网站建设企业怎么自己开发一个app软件
  • 基于springboot的技术交流和分享平台的设计与实现
  • Spring Boot 处理JSON的方法
  • 在Gin项目中使用API接口文档Swagger
  • asp.net 4.0网站开发高级视频教程订阅号怎么做免费的视频网站吗
  • 重庆响应式网站制作没有后台的网站怎么做排名
  • ENSP Pro Lab笔记:配置STP/RSTP/MSTP(1)
  • ajax 效果网站中国室内装饰设计网
  • 5-流程控制语句
  • Dify实战:调试技巧深度解析
  • Linux下Mysql初始化如,密码如何查找
  • 2025知识管理平台深度测评:从工具进化为智能决策引擎
  • 网站后台开发教程jsp网站缓存在哪
  • 网站页面怎么做的好看百度在西安的公司叫什么
  • Python 打印1-100的素数
  • 创建子进程时的一些细节
  • STM32 EC11旋转编码器扫描读取