今天为大家分享一个java语言编写的聊天系统程序,目前系统功能已经很全面,后续会进一步完善。整个系统界面漂亮,有完整得源码,希望大家可以喜欢。喜欢的帮忙点赞和关注。一起编程、一起进步
开发环境
开发语言为Java,开发环境Eclipse或者IDEA都可以,数据为MySQL。运行主程序,或者执行打开JAR文件即可以运行本程序。
系统框架
利用JDK自带的SWING框架开发。纯窗体模式,直接运行Main文件即可以。同时带有详细得设计文档。
主要功能
设计思路
随着计算机技术的飞速发展,尤其是互联网技术的兴起,使人们愈来愈倾向于通过网络来交流、传递消息。网络实时聊天系统正是这样一个被广泛应用的媒介。借助它,人们可以方便地进行实时对话。本次课程设计利用课程上所学的Java网络编程知识,开发出一个简易版本的多人和单人的聊小程序。系统的实现是基于TCP/IP通信协议,使用的是客户端/服务器模式,用到了Java里面的Swing、多线程、Socket等编程技术。通过直接使用Java提供的ServerSocket和ObjectInputStream等类将客户端和服务器端发送的各类消息封装实现消息的交换。需要实现的主要功能有
实现聊天室服务器端的要求:
①设计实现在特定端口上进行侦听,等待客户端的连接。
②用户确定服务器的侦听端口。
③系统能向已经连接到服务器端的用户发送系统消息。
④系统能统计在线人数。
⑤当系统停止服务时,设计程序应能断开所有的用户连接。
实现聊天室客户端的要求:
①系统能连接已经开启聊天服务的服务端。
②用户确定要连接服务器端的IP地址与端口号,连接后系统应能提供显示的用户名。
③当服务器端开启的话,实现用户的登录与注销。
④用户可以通过设计的系统向所有人或者某一个人发送消息
主要功能
本次课程设计实现的程序的关键功能有以下4点:
1 本程序分客户端和服务器端。服务器端启动一个socket连接,socket是多线程,接受从客户端发来的连接,如果更新成功,同时更新用户立表。
2 客户端启动,相应的就和服务器端建立一个socket,接受从服务器传递过来的消息,同时更新Textarea中,实时可以看到群里的内容。
3 服务器断开的时候,客户端能够收到提示,并且相应收到实时的消息,客户端能够收到消息提示,并且客户端退出。
4 能够一个服务器端和多个客户端进行通信
运行效果
(1) 启动服务器
启动服务端,启动服务器的端口,可以接受多个客户端发过来的,同时启动一个ServerThread,接受客户端发过的连接请求,发送消息等。
(2) 客户端启动
服务器端启动后,客户端可以进行启动,建立客户端和服务器的socket的连接,客户端可以看到当前在线用户,用户额聊天记录等,并且客户发送消息。发送的消息在服务端也能显示。
(3) 服务器关闭
当服务器关闭的时候,所有的客户端都会强制进行关闭。
清空用户列表
listModel.removeAllElements();
关闭并且释放SOCKET的相关资源
用户当前状态断开
(4) 群聊
多人聊天是指的,可以跟群里的所有人聊天,发送的消息,聊天室的所有人都能看到。
(4) 单聊
消息只能在发送和接受的人直接收到,其他的人不能收到。
关键代码
// 启动服务器
public void serverStart(int max, int port) throws java.net.BindException {
try {
clients = new ArrayList<ClientThread>();
serverSocket = new ServerSocket(port);
serverThread = new ServerThread(serverSocket, max);
serverThread.start();
isStart = true;
} catch (BindException e) {
isStart = false;
throw new BindException("端口号已被占用,请换一个!");
} catch (Exception e1) {
e1.printStackTrace();
isStart = false;
throw new BindException("启动服务器异常!");
}
}
// 关闭服务器
@SuppressWarnings("deprecation")
public void closeServer() {
try {
if (serverThread != null)
serverThread.stop();// 停止服务器线程
for (int i = clients.size() - 1; i >= 0; i--) {
// 给所有在线用户发送关闭命令
clients.get(i).getWriter().println(messageEncode("CLOSE"));
clients.get(i).getWriter().flush();
// 释放资源
clients.get(i).stop();// 停止此条为客户端服务的线程
clients.get(i).reader.close();
clients.get(i).writer.close();
clients.get(i).socket.close();
clients.remove(i);
}
if (serverSocket != null) {
serverSocket.close();// 关闭服务器端连接
}
listModel.removeAllElements();// 清空用户列表
isStart = false;
} catch (IOException e) {
e.printStackTrace();
isStart = true;
}
}
// 群发服务器消息
public void sendServerMessage(String message) {
for (int i = clients.size() - 1; i >= 0; i--) {
clients.get(i).getWriter()
.println(messageEncode("服务器:" + message + "(多人发送)"));
clients.get(i).getWriter().flush();
}
}
// 服务器线程
class ServerThread extends Thread {
private ServerSocket serverSocket;
private int max;// 人数上限
// 服务器线程的构造方法
public ServerThread(ServerSocket serverSocket, int max) {
this.serverSocket = serverSocket;
this.max = max;
}
public void run() {
while (true) {// 不停的等待客户端的链接
try {
Socket socket = serverSocket.accept();
if (clients.size() == max) {// 如果已达人数上限
BufferedReader r = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter w = new PrintWriter(
socket.getOutputStream());
// 接收客户端的基本用户信息
String inf = r.readLine();
System.out.println("307行-接收客户端基本信息" + inf);
inf = messageDecode(inf);
StringTokenizer st = new StringTokenizer(inf, "@");
User user = new User(st.nextToken(), st.nextToken());
// 反馈连接成功信息
w.println(messageEncode("MAX@服务器:对不起," + user.getName()
+ user.getIp() + ",服务器在线人数已达上限,请稍后尝试连接!"));
w.flush();
// 释放资源
r.close();
w.close();
socket.close();
continue;
}
ClientThread client = new ClientThread(socket);
client.start();// 开启对此客户端服务的线程
clients.add(client);
listModel.addElement(client.getUser().getName() + "("
+ client.getUser().getIp() + ")");// 更新在线列表
contentArea.append(client.getUser().getName()
+ client.getUser().getIp() + "上线!\r\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 为一个客户端服务的线程
class ClientThread extends Thread {
private Socket socket;
private BufferedReader reader;
private PrintWriter writer;
private User user;
public BufferedReader getReader() {
return reader;
}
public PrintWriter getWriter() {
return writer;
}
public User getUser() {
return user;
}
// 客户端线程的构造方法
public ClientThread(Socket socket) {
try {
this.socket = socket;
reader = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
writer = new PrintWriter(socket.getOutputStream());
// 接收客户端的基本用户信息
String inf = reader.readLine();
System.out.println("361行-客户端线程构造方法" + inf);
inf = messageDecode(inf);
StringTokenizer st = new StringTokenizer(inf, "@");
user = new User(st.nextToken(), st.nextToken());
// 反馈连接成功信息
writer.println(messageEncode(user.getName() + user.getIp()
+ "与服务器连接成功!"));
writer.flush();
// 反馈当前在线用户信息
if (clients.size() > 0) {
String temp = "";
for (int i = clients.size() - 1; i >= 0; i--) {
temp += (clients.get(i).getUser().getName() + "@" + clients
.get(i).getUser().getIp())
+ "@";
}
System.out.println("USERLIST@" + clients.size() + "@"
+ temp);
System.out.println("379:添加用户的加密:"
+ messageEncode("USERLIST@" + clients.size() + "@"
+ temp));
writer.println(messageEncode("USERLIST@" + clients.size()
+ "@" + temp));
writer.flush();
}
// 向所有在线用户发送该用户上线命令
for (int i = clients.size() - 1; i >= 0; i--) {
System.out.println("385行-发送在线命令位置:"
+ messageEncode("ADD@" + user.getName()
+ user.getIp()));
clients.get(i)
.getWriter()
.println(
messageEncode("ADD@" + user.getName()
+ user.getIp()));
clients.get(i).getWriter().flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@SuppressWarnings("deprecation")
public void run() {// 不断接收客户端的消息,进行处理。
String message = null;
while (true) {
try {
message = reader.readLine();// 接收客户端消息
System.out.println("397行-接收客户端消息" + message);
message = messageDecode(message);
if (message.equals("CLOSE"))// 下线命令
{
contentArea.append(this.getUser().getName()
+ this.getUser().getIp() + "下线!\r\n");
// 断开连接释放资源
reader.close();
writer.close();
socket.close();
// 向所有在线用户发送该用户的下线命令
for (int i = clients.size() - 1; i >= 0; i--) {
System.out.println("414行-发送下线命令:"
+ messageEncode("DELETE@" + user.getName()
+ "@" + user.getIp()));
clients.get(i)
.getWriter()
.println(
messageEncode("DELETE@"
+ user.getName() + "@"
+ user.getIp()));
clients.get(i).getWriter().flush();
}
listModel.removeElement(user.getName() + "("
+ user.getIp() + ")");
listModel.removeElement(user.getName());// 更新在线列表
// 删除此条客户端服务线程
for (int i = clients.size() - 1; i >= 0; i--) {
System.out.println(user.getIp());
System.out
.println(clients.get(i).getUser().getIp());
if (clients.get(i).getUser().getIp()
.equals(user.getIp())) {
ClientThread temp = clients.get(i);
clients.remove(i);// 删除此用户的服务线程
temp.stop();// 停止这条服务线程
return;
}
}
} else {
System.out.println("429行-调用转发消息之前的messag为" + message);
dispatcherMessage(message);// 转发消息
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
项目总结
经过两个星期的不断工作,我们终于完成基于局域网聊天室程序,虽然大体功能完成了,但是系统存在界面不是很美观,不需要登录就可以进入聊天系统;系统的传递和解析消息都要通过解析字符串来进行,当输入信息有特殊符号的时候,程序就会报错,系统健壮性还不够强大。下一步可以改成xml来进行消息的传递。
我们小组的题目基于Java的聊天小程序,在平时学习的知识基础上,自己动手敲代码,写设计文档,通过自己的不断努力,在两个星期的时间内,终于把系统完成了,达到了预期的目标。经过了这次课程设计,我加深了对java Swing程序的原理和运行机制,熟练掌握了JDialog,JPanel,JFrame,JMenuBar的使用和java事件的使用,socket事件,java多线程编程的认识。并且能把他们运用到实际的程序中去,对我以后的学习有很大的帮助。