基于C/S模式的简单聊天室
基于C/S模式的简单聊天室
要求:
使用Socket实现网上聊天室,要求基于TCP或UDP协议,用户可以通过客户端连接到服务器端并进行聊天,聊天时可以启动多个客户端;服务器启动后,接收客户端发来的用户名和验证信息,验证通过则可以加入聊天室,当客户退出聊天时在聊天室公告改用户退出信息;要求界面美观。
- 流程图

- 运行结果



- 代码重现
客户端界面
// ClientFrame.java
package client;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Vector;
import javax.swing.*;
public class ClientFrame extends JFrame {
JTextField field1; // 信息发送文本框
JTextField usernamefield1; // 用户名文本框
JPasswordField passwordfield2; // 密码文本框
JLabel label1; // 显示用户名
JLabel label2; // 显示密码
JPanel panel;// 下方面板
JTextArea area;// 信息接收文本域
JButton button;// 发送按钮
String userName;// 用户名称
String passWord;// 用户密码
Vector<String> username = new Vector(6);
Vector<String> password = new Vector(6);
int flag;// 密码验证是否正确的标志,flag=1成功,flag=0失败
boolean is_empty = true;// 密码验证是否为空的标志
ChatRoomClient client;// 客户端连接对象
public ClientFrame() {
setUser();
do {
try {
// 手动输入IP地址进行连接服务器
//String host = JOptionPane.showInputDialog(this, "请输入服务器IP地址");
// 自动获取IP地址连接服务器
String host = InetAddress.getLocalHost().getHostAddress().toString();
if (host == null) {
System.exit(0);// 如果host是空的,则关闭程序
}
client = new ChatRoomClient(host, 5678);// 连接服务器的5678接口
} catch (IOException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(this, "网络无法连接,请重新设置参数");
}
} while (client == null);// 如果客户端没有关闭,则一直连接
while(is_empty) {// 验证输入的用户名、密码是否为空
field1 = new JTextField(25);
String str = JOptionPane.showInputDialog(this, "请输入用户名:");
userName = str.trim();
usernamefield1 = new JTextField(15);
label1 = new JLabel(userName);
String str2 = JOptionPane.showInputDialog(this, "请输入"+userName+"的密码:");
passWord = str2.trim();
passwordfield2 = new JPasswordField(15);
passwordfield2.setEchoChar('*');
label2 = new JLabel(passWord);
// 空:while循环重新输入,否则直接进入客户端client
is_empty = is_empty(userName,passWord);
// 验证用户名、密码是否正确
int yz = is_true(userName,passWord);
if(yz == 1) {
area = new JTextArea(20, 15);
area.setEditable(false);
button = new JButton("发送");
panel = new JPanel();
init();
addEventHandler();
}else {
if(is_empty == false) {
JOptionPane.showMessageDialog(null, "账号或密码错误,请重新输入", "提示", 1);
}
is_empty = true;// 账号或密码错误,将用户名密码置空,is_empty置为true
}
}
}
// 验证用户名、密码是否为空
public boolean is_empty(String userName, String passWord) {
// TODO Auto-generated method stub
if(userName.length() == 0) {
is_empty = true;
JOptionPane.showMessageDialog(this, "用户名不能为空");
}else if(passWord.length() == 0){
is_empty = true;
JOptionPane.showMessageDialog(this, "密码不能为空");
}else {
is_empty = false;
}
return is_empty;
}
// 设定初始的用户和密码
void setUser() {
username.add("张三");
username.add("李四");
username.add("王五");
password.add("zs123");
password.add("ls123");
password.add("ww123");
}
// 初始化方法
public void init() {
//add();
JScrollPane jsp = new JScrollPane(area);// 添加滚动条
this.setTitle(" 602聊天室");
this.add(jsp);
panel.add(label1);
//panel.add(label2);
panel.add(field1);
//panel.add(passwordfield2);
panel.add(button);
this.add(panel, BorderLayout.SOUTH);// 下方面板,布局位置为南
}
// 展示窗口
public void showMe() {
this.pack();// 调整此窗口的大小,以适合其子组件的首选大小和布局。
this.setVisible(true);// 窗口可显示
this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);// 点击窗口叉,不做任何操作
new ReadMessageThread().start();// 开启线程
}
// 验证用户名密码是否一致
public int is_true(String userName,String passWord) {
// System.out.println(username.size());
flag = 0;
for(int i=0;i<username.size();i++) {
if(username.get(i).equals(userName) && password.get(i).equals(passWord)){
flag = 1;
}
}
if(flag == 1) {
JOptionPane.showMessageDialog(null, "登录成功", "提示", -1);
}
// else {
// JOptionPane.showMessageDialog(null, "账号或密码错误,请重新输入", "提示", 1);
// field1.setText("");
// passwordfield2.setText("");
// new ClientFrame().showMe();
// }
return flag;
}
// 添加监听方法
public void addEventHandler() {
button.addActionListener(new ActionListener() {// 开启按钮监听
public void actionPerformed(ActionEvent e) {
// 判断消息是否为空
if(field1.getText().length() == 0) {
JOptionPane.showMessageDialog(null, "消息不能为空", "注意", 1);
is_empty = true;
}else {
is_empty = false;
}
if(is_empty == false) {
client.sendMessage(userName + ":" + field1.getText());// 向服务器发送文本内容
field1.setText("");// 输入框置空
}
}
});
// 开启窗口监听
this.addWindowListener(new WindowAdapter() {
// 窗口关闭时
public void windowClosing(WindowEvent atg0) {
int op = JOptionPane.showConfirmDialog(ClientFrame.this,
"确定要退出聊天室吗?", "确定", JOptionPane.YES_NO_OPTION);// 弹出提示框
if (op == JOptionPane.YES_OPTION) {// 如果选择是
client.sendMessage("%EXIT%:" + userName);// 发送消息
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
client.close();// 关闭客户端连接
System.exit(0);// 关闭程序
}
}
});
}
private class ReadMessageThread extends Thread {
public void run() {
while (true) {
String str = client.reciveMessage();// 客户端收到服务器发来的文本内容
area.append(str + "\n");// 向文本框添加文本内容
}
}
}
public static void main(String[] args) {
new ClientFrame().showMe();
}
}
客户端
// ChatRoomClient.java
package client;
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.Vector;
import javax.swing.JOptionPane;
public class ChatRoomClient {
Socket s;// 客户端套接字
BufferedReader br;// 读取字节流
PrintWriter pw;// 写入字节流
public ChatRoomClient(String host, int port) throws UnknownHostException,
IOException {
s = new Socket(host, port);// 连接服务器
br = new BufferedReader(new InputStreamReader(s.getInputStream()));// 字节流读取套接字输入流
pw = new PrintWriter(s.getOutputStream());// 字节流写入套接字输出流
}
public void sendMessage(String str) {// 发送消息
pw.println(str);
pw.flush();
}
public String reciveMessage() {// 获取消息
try {
String xx = br.readLine();
return xx;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public void close() {// 关闭套接字连接
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务器
// ChatRoomServer.java
package server;
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.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
public class ChatRoomServer {
ServerSocket serversocket;//服务器套接字
HashSet<Socket> allSockets;//客户端套接字集合
public ChatRoomServer() {
try {
serversocket = new ServerSocket(5678);//开启服务器5678接口
} catch (IOException e) {
e.printStackTrace();
}
allSockets = new HashSet<Socket>();//实例化客户端套接字结合
}
public void startService() throws IOException {
System.out.println("服务器已成功开启");
while (true) {
Socket s = serversocket.accept();//获得一个客户端的连接
System.out.println("用户已进入聊天室");
allSockets.add(s);//将客户端连接的套接字放到集合中
new ServerThread(s).start();//为此客户端单独创建一个事务处理线程
}
}
private class ServerThread extends Thread {//线程类
Socket s;
public ServerThread(Socket s) {//通过构造方法获取客户端连接
this.s = s;
}
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(
s.getInputStream()));//将客户端套接字输入流转换为字节流读取
while (true) {//无限循环
String str = br.readLine();//读取到一行之后,则赋值给字符串
if (str.indexOf("%EXIT%") == 0) {//如果文本内容中包括"%EXIT%"
allSockets.remove(s);//集合删除此客户端连接
sendMessageTOAllClient("-" + str.split(":")[1]
+ "-已退出聊天室");//服务器向所有客户端接口发送退出通知
s.close();//关闭此客户端连接
return;//结束循环
}
sendMessageTOAllClient(str);//向所有客户端此客户端发来的文本信息
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMessageTOAllClient(String message) throws IOException {//向所有客户端发送文本内容
Date date = new Date();//创建时间类
SimpleDateFormat df = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");//在文本后面添加时间
System.out.println(message + "\t[" + df.format(date) + "]");
for (Socket s : allSockets) {//循环集合中所有的客户端连接
PrintWriter pw = new PrintWriter(s.getOutputStream());//创建输出流
pw.println(message + "\t[" + df.format(date) + "]");//输写入文本内容
pw.flush();//输出流刷新
}
}
}
public static void main(String[] args) {
try {
new ChatRoomServer().startService();
} catch (IOException e) {
e.printStackTrace();
}
}
}
需要详细报告或者有问题可以加QQ: 2953094905
