一、题目描述
题目实现:不同的客户端之间需要进行通信,一个客户端与其他的多个客户端进行通信,实现群聊功能。
实现一个客户端与其他多个客户端进行通信,运行程序,服务器启动后,启动3个客户端程序,然后通过第一个客户端向另外两个客户端发送信息,则另外的两个客户端都会收到服务器发送的信息。
二、解题思路
创建一个服务类:ClientOneToManyServerFrame,继承JFrame类
定义一个createSocket()方法,用于创建服务Socket和监听客户端程序。以及创建并启动线程对象并将接收到的客户端发送的信息转发给其他客户端。
创建一个客户端类:ClientOneToManyClientFrame,继承JFrame类
定义一个createClientSocket()方法,用于创建与服务器连接的Socket对象,输出流对象,以及启动线程对象接收服务器端转发的信息。
技术重点:
在服务器端通过线程对客户端发送的信息进行监听,当有客户端发送信息时,就会将该信息发送给其他已经登录到服务器的客户端,但是不会向发送方发送该信息,在客户端也通过线程来监听服务器转发的信息。 (1)在服务器端创建线程类ServerThread,用于接收客户端发送的信息,并转发给其他已经连接到服务器的客户端。
(2)在客户端创建线程类ClientThread,用于接收服务器端转发的客户端信息,并在客户端的文本域中显示接收到的信息。
启动多个客户端:
1、把项目打成jar包:利用maven 的clean install
会在target目录下生成jar包
2、进入target目录,使用java -cp的命令运行指定的类
java -cp 命令中 cp 指的就是classpath。使用该命令可以运行jar中的某个指定的类(要包含全路径的包名)
进入cmd命令模式
运行服务端
java -cp basics98-1.0-SNAPSHOT.jar com.xiaoxuzhu.ClientOneToManyServerFrame
运行多个客户端
java -cp basics98-1.0-SNAPSHOT.jar com.xiaoxuzhu.ClientOneToManyClientFrame
三、代码详解
ClientOneToManyServerFrame
package com.xiaoxuzhu;
import java.awt.BorderLayout;
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.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class ClientOneToManyServerFrame extends JFrame {
private JTextArea ta_info;
private ServerSocket server; // 声明ServerSocket对象
private Socket socket; // 声明Socket对象socket
private Vector<Socket> vector = new Vector<Socket>();// 用于存储连接到服务器的客户端套接字对象
public void createSocket() {
try {
server = new ServerSocket(9527);
while (true) {
ta_info.append("等待新客户连接......\n");
socket = server.accept();// 创建套接字对象
vector.add(socket);// 将套接字对象添加到向量对象中
ta_info.append("客户端连接成功。" + socket + "\n");
new ServerThread(socket).start();// 创建并启动线程对象
}
} catch (IOException e) {
e.printStackTrace();
}
}
class ServerThread extends Thread {
Socket socket;
public ServerThread(Socket socket) {
this.socket = socket;
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));// 创建输入流对象
while (true) {
String info = in.readLine();// 读取信息
for (Socket s : vector) {// 遍历所有客户端套接字对象
if (s != socket) {// 如果不是发送信息的套接字对象
PrintWriter out = new PrintWriter(s
.getOutputStream(), true);// 创建输出流对象
out.println(info);// 发送信息
out.flush();// 刷新输出缓冲区
}
}
}
} catch (IOException e) {
ta_info.append(socket + "已经退出。\n");
vector.remove(socket);// 移除退出的客户端套接字
}
}
}
public static void main(String args[]) {
ClientOneToManyServerFrame frame = new ClientOneToManyServerFrame();
frame.setVisible(true);
frame.createSocket();
}
public ClientOneToManyServerFrame() {
super();
setTitle("客户端一对多通信——服务器端程序");
setBounds(100, 100, 385, 266);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JScrollPane scrollPane = new JScrollPane();
getContentPane().add(scrollPane, BorderLayout.CENTER);
ta_info = new JTextArea();
scrollPane.setViewportView(ta_info);
}
}
ClientOneToManyClientFrame
package com.xiaoxuzhu;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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 javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class ClientOneToManyClientFrame extends JFrame{
private JTextArea ta_info;
private JTextField tf_send;
PrintWriter out;// 声明输出流对象
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ClientOneToManyClientFrame frame = new ClientOneToManyClientFrame();
frame.setVisible(true);
frame.createClientSocket();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void createClientSocket() {
try {
Socket socket = new Socket("127.0.0.1", 9527);// 创建套接字对象
out = new PrintWriter(socket.getOutputStream(), true);// 创建输出流对象
new ClientThread(socket).start();// 创建并启动线程对象
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
class ClientThread extends Thread {
Socket socket;
public ClientThread(Socket socket) {
this.socket = socket;
}
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));// 创建输入流对象
while (true) {
String info = in.readLine();// 读取信息
ta_info.append(info + "\n");// 在文本域中显示信息
if (info.equals("88")) {
break;// 结束线程
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void send() {
String info = tf_send.getText();// 获得输入的信息
if (info.equals("")) {
return;// 如果没输入信息则返回,即不发送
}
if (info.equals("88")) {
System.exit(0);// 如果没输入信息是88,则退出
}
out.println(info);// 发送信息
out.flush();// 刷新输出缓冲区
tf_send.setText(null);// 清空文本框
}
public ClientOneToManyClientFrame() {
super();
setTitle("客户端一对多通信——客户端程序");
setBounds(100, 100, 385, 266);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel = new JPanel();
getContentPane().add(panel, BorderLayout.SOUTH);
final JLabel label = new JLabel();
label.setText("输入聊天内容:");
panel.add(label);
tf_send = new JTextField();
tf_send.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
send();// 调用方法发送信息
}
});
tf_send.setPreferredSize(new Dimension(180, 25));
panel.add(tf_send);
final JButton button = new JButton();
button.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
send();// 调用方法发送信息
}
});
button.setText("发 送");
panel.add(button);
final JScrollPane scrollPane = new JScrollPane();
getContentPane().add(scrollPane, BorderLayout.CENTER);
ta_info = new JTextArea();
scrollPane.setViewportView(ta_info);
//
}
}
服务器启动
客户端1向其他客户端群发信息
客户端2接收到的信息
客户端3接收到的信息
以上就是Java聊天室之实现客户端群聊功能的详细内容,更多关于Java聊天室的资料请关注编程网其它相关文章!