练习:
网络编程:客户端和服务器端多线程的通信
需求实现:
- 建立服务端和客户端
- 客户端与服务端可以正常通信
- 一个客户端连接到服务端后,服务端向所有客户端广播消息
- 在客户端命令行输入内容后,服务端接收内容并广播到所有客户端
- 客户端输入exit后,服务端下线此客户端
- 客户端先输入exit,再输入q后,关闭客户端程序
代码如下:
服务端:
/**
* @Description 一对多的通信
* 整个多线程的通信要注意:
* 1. 服务端一直在等待socket的接入
* 2. socket上线构造函数可以直接输出
* 3. serverThread线程处理的是获取socket管道的通信,发送给所有的客户端,客户端下限后去除clients
* @Date 2023/6/29 15:21
*/
public class MultiThreadServer {
List<ServerThread> clients = new ArrayList<>();
public static void main(String[] args) throws IOException {
new MultiThreadServer().run();
}
private void run() throws IOException {
ServerSocket serverSocket = new ServerSocket(6060);
while (true){
Socket socket = serverSocket.accept();
ServerThread st = new ServerThread(socket,clients);
new Thread(st).start();
}
}
class ServerThread implements Runnable {
private Socket socket;
private String name;
private BufferedReader reader;
private PrintWriter writer;
private List<ServerThread> clients;
public ServerThread(Socket socket,List<ServerThread> clients) throws IOException {
this.socket = socket;
this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.writer = new PrintWriter(socket.getOutputStream(),true);
this.name = reader.readLine()+"["+socket.getInetAddress()+":"+socket.getPort()+"]";
this.clients = clients;
clients.add(this);
System.out.println(name+"上线了");
sendAll(name+"上线了");
}
@Override
public void run() {
String line = null;
while (true){
try {
if ((line = reader.readLine()) != null) {
System.out.println(this.name+":"+line);
sendAll(this.name+":"+line);
if("exit".equalsIgnoreCase(line)) break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(this.name+"下线了");
sendAll(name+"下线了");
clients.remove(this);
if(this.socket != null) {
try {
this.socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void sendAll(String msg){
for (ServerThread client : this.clients) {
client.writer.println(msg);
}
}
}
}
客户端:
/**
* @Description 客户端的多线程
* @Date 2023/6/29 16:25
*/
public class ClientCmd {
Socket socket = null;
BufferedReader reader = null;
BufferedReader br = null;
public static void main(String[] args) {
new ClientCmd().run();
}
private void run(){
try {
socket = new Socket("127.0.0.1",6060);
reader = new BufferedReader(new InputStreamReader(System.in));
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
pw.println("张老师");
String str = null;
new Thread(new ClientCmd.ClientThread()).start();
while((str = reader.readLine())!= null) {
// 输入exit后线程退出了,但reader还在等待控制台输入
if("q".equals(str)) break;
pw.println(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(reader!= null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class ClientThread implements Runnable {
@Override
public void run() {
String res = null;
try {
while ((res = br.readLine())!=null){
System.out.println(res);
if("exit".equalsIgnoreCase(res)) break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}