基于C/S模式的简易聊天室
一、任务简要描述
移动互联网技术的广泛应用为人们提供了非常便捷的沟通方式。QQ、微信和微博等是便携式聊天系统的典型代表,它们的功能非常强大。
本系统利用TCP/IP协议的Socket和ServerSocket类,实现基于C/S模式的简易聊天室。该聊天室包括服务端和客户端两部分,服务端是客户端发送消息的中转站;客户端之间可以直接通信,也可以与服务器通信。聊天结束后客户端断开与服务端的连接,服务器也可以停止信息中转服务。
二、系统需求分析
本系统采用C/S软件架构,服务器端负责监听客户端发来的消息,并把消息转发到对应的客户端;客户端可以向指定的人发送消息,并接受其他客户端发来的信息。服务器端的功能如图2-1所示,服务端的主界面如图2-2所示;客户端的功能如图2-3所示,客户端的主界面如图2-4所示。
服务器端的功能 图2-1
服务器端主界面 图2-2
客户端的功能 图2-3
客户端的主界面 图2-4
2.1功能描述——服务器端
1、信息处理
①服务器作为客户端之间发送消息的中转站,需要接受并转发客 户端之间的信息。
②服务器也可以向指定的客户端发送系统信息,也可以向所有客 户端发送信息。
③跟踪用户登录情况,并更新用户数量。
2、服务器设置
①服务器端设置服务器的IP地址和通信的端口号,便于客户端与服务器建立连接。
②启动服务器准备进行信息中转与发送。
③停止服务器服务,客户之间不能通信。
2.2功能描述——客户端
1、信息处理
①接受服务器和其他客户端向本地发送的信息。
②本地客户端向服务器和其他客户端发送信息。
2、客户端设置
①客户端需要连接服务器的IP地址和端口号。
②启动客户端,根据服务器的IP地址和端口号登录到指定的服务器。
③停止客户端,注销与服务器的连接,停止服务器的通信。
三、系统设计
3.1类及UML设计——服务器端
根据服务器端功能需要,服务器端包括6个源文件,它们是ServerRoom.java、ServerReceive.java、ServerListen.java、Node.java、UserList.java和ServerPortConfig.java,下面分别介绍 它们的功能及UML图。
1、ServerRoom.java
该文件包含一个publicServer类,该类继承JFrame实现ActionListener接口,封装了服务器界面、服务器端对用户上线和下线的监听以及利用ServerReceive类来实现服务器端的消息收发处理功能,启动服务器的main()方法在该类中。ServerPort是一个静态成员,设置服务器端口号,initServer()方法初始化服务器端的界面,startServer()方法启动服务stopServer()方法停止服务,sendStopToAll()发送服务器停止服务消息给所有客户端,sendMSGToAll()给所有客户端发送信息,sendServerMSGToClient()方法把服务器的消息发送给客户端,actionPerformed()实现ActionListen接口中的方法,点击设置、端口、启动服务、停止服务、退出系统以及发送等按钮后激活该方法。UML如图3-1所示。
ServerRoom类图 图3-1
信息发送给服务器和在线用户,run()实现Runnable接口中的方法,用来向所有人或者指定用户发送信息,并且用户下线后更新用户列表。UML如图3-2所示。
ServerReceive类 图3-2
1、ServerListen.java
该文件包含一个publicServerListen类,该类实现Runnable接口,用来监听客户端用户上线与下线的情况,run()实现Runnable接口中的方法,该方法实现当有用户登录服务器时向用户链表中增加新用户、当用户断开服务器时从用户链表中删除该用户等功能。
2、Node
该文件包含public Node类,该类封装了用户链表节点,通过链表的形式保存用户信息,用户信息包括用户名、用户的Socket套接字对象、对象输入流与对象输出流用来接收和发送信息以及next为下一个用户的引用。
5、UserList.java
该文件包含public UserList类,该类封装了用户链表,addUser()方法用户链表添加用户、deleteUser()方法从用户链表中删除用户、getCount()方法获得用户链表中的用户数
findUser()方法通过索引号和用户名查找等功能。
6、ServerPortConfig.java
该文件包含public ServerPortConfig类,该类继承JDialog类并实现ActionListener接口,通过界面配置服务器端口,serverPortInit()方法初始化服务端口,actionPerformed()实现ActionListener()接口中的方法,完成点击保存按钮和取消按钮的操作。
3.2类及UML设计——客户端
根据聊天室客户端功能的需要,客户端包括4个源文件,它们是ClientRoom.java、ClientConnect.java、ClientInfoConfig.java和ClientReceive.java,下面分别介绍它们的功能。
1、ClientRoom.java
该文件包含public ClientRoom类,该类继承JFrame类和实现ActionListener接口,封装了客户端界面,完成客户端与服务器的连接、断开与服务器的连接、向指定用户或者所有用户发送信息等功能。main()方法启动客户端,initClient()方法初始化客户端界面,connectServer()方法连接服务器,disConnectServer()方法断开服务器连接,sendMessage()方法向特定用户发送消息,actionPerformed()实现ActionListener接口中的方法,实现按钮动作的处理。
2、ClientConnConfig.java
该文件包含public ClientInfoConfig类,该类继承JDialog类实现ActionListener接口,封装了客户端连接服务器的配置,用来指定服务器端的IP地址和监听的端口号,getServerIP()方法获得服务器的IP地址,getServerPort()方法获得服务器端口号,clientConnInit()方法初始化连接配置窗口,actionPerformed()实现ActionListener接口中的方法,实现保存客户端配置的按钮功能
3、ClientInfoConfig.java
该文件包含public ClientInfoConfig类,该类继承JDialog类实现ActionListener接口,完成用户配置自己的登录用户名的功能,initInfoConfig()方法初始化配置用户名登录窗口,actionPerformed()实现ActionListener接口中的方法,当点击保存按钮之后激活该方法。
4、ClientReceive.java
该文件包含public ClientReceive类,该类实现Runnable接口,实现客户端接收服务器转发的消息,以及向特定用户或者服务器发送信息的功能。
四、系统实现
1 服务端监听类 2 package server; 3 import javax.swing.*; 4 import java.io.*; 5 import java.net.*; 6 /** 7 * 服务端的监听类,实现Runnable接口 8 */ 9 public class ServerListen implements Runnable { 10 private Node clientNode; 11 private UserList userList; //用户链表 12 private ServerSocket serverSocket; 13 private ServerReceive receiveThread; 14 private JComboBox comboboxUser; 15 private JTextArea textAreaChatMSG; 16 private JTextField textfieldUserConnCount; 17 public boolean isStop; 18 /** 19 * 构造方法,初始化服务端的监听情况 20 */ 21 public ServerListen(ServerSocket serverSocket, JComboBox comboboxUser, 22 JTextArea textAreaChatMSG, JTextField textfieldUserConnCount, UserList userList) { 23 this.serverSocket = serverSocket; 24 this.comboboxUser = comboboxUser; 25 this.textAreaChatMSG = textAreaChatMSG; 26 this.textfieldUserConnCount = textfieldUserConnCount; 27 this.userList = userList; 28 isStop = false; 29 } 30 /** 31 * 实现Runnable接口中的run方法 32 * 在服务端监听用户上线和下线的情况 33 */ 34 public void run() {//实现接口Runnable中的run方法 35 while(! isStop && ! serverSocket.isClosed()) { 36 try { 37 clientNode = new Node(); 38 clientNode.socket = serverSocket.accept();//接收客户端连接 39 //获得客户端的对象输出流 40 clientNode.output = new 41 ObjectOutputStream(clientNode.socket.getOutputStream()); 42 clientNode.output.flush(); 43 //获得客户端的对象输入流 44 clientNode.input = new ObjectInputStream(clientNode.socket.getInputStream()); 45 clientNode.userName = (String)clientNode.input.readObject(); 46 //在文本框显示登录信息 47 textAreaChatMSG.append("用户 " + clientNode.userName + " 上线" +"\n"); 48 //记录连接的用户名 49 comboboxUser.addItem(clientNode.userName); 50 userList.addUser(clientNode);//把新用户加入用户列表 51 //修改用户上线的数量 52 textfieldUserConnCount.setText("在线用户" + userList.getCount() + "人\n"); 53 receiveThread = new ServerReceive(textAreaChatMSG, userList, 54 textfieldUserConnCount, comboboxUser, clientNode); 55 new Thread((Runnable) receiveThread).start();//启动接收线程 56 //System.out.println("ServerListen run!"); 57 } 58 catch(Exception e) { 59 } 60 } 61 } 62 }
1、配置服务器和客户端
(1)配置服务器
启动服务器后弹出主界面如图4-1所示,然后进行端口设置如图4-2所示。
服务器主界面 图4-1
配置服务器端口号 图4-2
(1)配置客户端
启动客户端后的主界面如图4-3所示,配置用户名如图4-4所示,配置与服务器的连接如图4-5所示。
客户端主界面 图4-3
设置用户名 图4-4
设置客户端与服务器的连接信息 图4-5
1、客户端与服务器端通信
服务器端“启动服务”、客户端“登录”之后,客户端与服务器端可以进行通信。服务器端可以给所有人或者指定客户端发送消息,如图4-6所示。
客户端可以给服务器或者指定的其他客户发送信息,如图4-7所示。
服务端给指定客户端发送信息 图4-6
客户端给所有人发送消息 图4-7
五、问题及解决
在最初设计时,没有考虑到多线程的问题,发现问题后我做了修改。
总的思路是采用c/s的方式,client借助socket完成向server的发送和接受两个工作,当然了,为了体现出真实情况下的双工的特点,发送和接受是需要开两个线程的,也就是说,一个用户需要自己管理两个线程。server则相对来讲比较复杂,因为这里面涉及到了调度,server需要有发送消息给在线client的线程(这个线程要做的事情就是只要有消息就要把消息发到所有的用户的窗口),以及接受client发来的消息的线程(这个线程要做的事情就是将接收到的消息全部交给发送消息的线程,于是这两个线程之间的通信问题也是实现上的一个关键~),为了使得所有的用户消息是同步的,server需要管理一个用户线程的列表,用以实现用户的行为的控制,于是乎这就要求只要有用户请求连接服务器,服务器就要为用户新建一个线程,那么client 和server 之间靠什么来进行联系呢,那就是我们的socket了。
六、系统特色与创新
本系统实现简单聊天室功能,服务器端可以向指定用户或者所有用户发送消息,客户端可以向指定用户或者所有用户发送消息;当用户登录服务器时,服务器及时更新用户列表并把所有用户更新的信息发给所有在线用户。本项目采用的主要知识点有基于流套接字的网络编程、多线程编程、GUI编程等。
七、个人心得与体会
本系统提供了聊天室最基本的通信功能,通过本次作业和自己的学习,我受益匪浅,对Java编程中用到的IO、多线程、网络编程、图形用户界面与事件处理都有了更深的理解并在实际中得到应用。对于接触Java语言时间不长的我,聊天室未免有些简陋,后续我还会尝试更加完善系统功能,使系统能像QQ等即时通信软件一样发送文件和图片等,服务器端可以保存所有用户的通信信息,而客户端可以保存自己的通信信息。