使用多线程+网络编程实现一个服务器对多个客户端
在该程序中用到的知识点
- java的BIO
- ServerSocket和Socket 网络编程
- 多线程的知识(个人认为重要)
实现的思路
服务器端(使用多个线程)
- 在客户端需要有一个集合来存储已经连接上的客户端, 如果客户端断开连接则需要从集合中删除
- 创建一个线程来处理客户端的连接
- 每一个客户端的连接都需要一个线程来接收客户端的请求
- 使用主线程来给客户端发送数据(轮询客户端集合中的Socket给客户端发送数据)
客户端(使用两个线程)
- 首先创建一个线程来接收服务器端的数据
- 使用主线程来给服务器端发送数据
效果的演示
- 启动服务器端

-
启动客户端

启动客户端后,服务器端可以监听到连接

- 在客户端中发送数据在服务端可以接收到


4、 在服务器端发送数据,在已经连接上的客户端中可以接受到消息


-
客户端退出,服务器端有提示

-
服务器端退出,所有的客户端有提示,并且客户端全部断开连接

代码演示
服务器端
public class Server {
public static void main(String[] args) {
List<Socket> socketList = new ArrayList<>();
// 开启线程接收客户端的连接
new Thread(new AcceptSocket(socketList)).start();
while (true) {
Scanner scanner = new Scanner(System.in);
String sendInfo = scanner.nextLine();
// 循环向所有的客户端发送消息
socketList.forEach(socket -> {
try {
PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
printWriter.println(sendInfo);
printWriter.flush();
} catch (SocketException e) {
System.out.println(1);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
}
// 接收客户端Socket线程
class AcceptSocket implements Runnable {
List<Socket> socketList;
public AcceptSocket(List<Socket> socketList) {
this.socketList = socketList;
}
@Override
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(9000);
System.out.println("监听客户端的连接");
// 循环接收客户端的请求
while (true) {
Socket socket = serverSocket.accept();
// 接收到后加入到 socketList
socketList.add(socket);
// 开启处理客户端线程
new Thread(new HandleSocket(socket, socketList)).start();
}
} catch (SocketException e) {
System.out.println(2);
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭连接
try {
if (null != serverSocket) {
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 处理客户端Socket线程
class HandleSocket implements Runnable {
Socket socket;
List<Socket> socketList;
public HandleSocket(Socket socket, List<Socket> socketList) {
this.socket = socket;
this.socketList = socketList;
}
@Override
public void run() {
BufferedReader bufferedReader = null;
try {
// 读取客户端发来的数据
bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("等待读取客户端:" + socket.getLocalAddress().toString().substring(1) + ":" + socket.getPort() + " 的消息");
while (true) {
String clientInfo = bufferedReader.readLine();
System.out.println(socket.getLocalAddress().toString().substring(1) + ":" + socket.getPort() + "发送的消息是:" + clientInfo);
}
} catch (SocketException e) {
// 强制关闭连接后的处理
System.out.println(socket.getLocalAddress().toString().substring(1) + ":" + socket.getPort() + "断开连接");
// 将该连接从socketList中移除
socketList.remove(socket);
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭连接
try {
if (null != bufferedReader) {
bufferedReader.close();
}
if (null != socket) {
bufferedReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端
public class Client {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Socket socket = null;
PrintWriter printWriter = null;
try {
socket = new Socket("localhost", 9000);
printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
//开启线程接收服务端的消息
new Thread(new AcceptServer(socket)).start();
System.out.println("可以给服务器端发送数据了");
while (true) {
// 给服务端发送消息
String sendInfo = scanner.nextLine();
printWriter.println(sendInfo);
printWriter.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭连接
try {
if (null != socket) {
socket.close();
}
if (null != printWriter) {
printWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class AcceptServer implements Runnable {
Socket socket;
public AcceptServer(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
String serverInfo = bufferedReader.readLine();
System.out.println("服务器的消息为:" + serverInfo);
}
} catch (SocketException e) {
System.out.println("服务器异常关闭");
// 退出
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭连接
try {
if (null != bufferedReader) {
bufferedReader.close();
}
if (null != socket) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
本文展示了如何使用Java的BIO模型,通过多线程技术和网络编程实现一个服务器同时处理多个客户端连接。服务器端创建线程接收客户端连接,并为每个连接创建单独的线程进行数据交互。客户端也采用双线程模型,一个接收服务器数据,一个发送数据。当客户端断开或服务器退出时,会进行相应的通知和资源清理。
对多(客户端)&spm=1001.2101.3001.5002&articleId=123360037&d=1&t=3&u=74e0058f9cbd41b4b67057e7b4f298b4)
1964

被折叠的 条评论
为什么被折叠?



