资源描述
java课程设计报告java聊天室
79
2020年4月19日
文档仅供参考
Java聊天室课程设计
一、 需求分析
1.1开发背景
在信息化社会的今天,网络飞速发展,人们对网络的依赖越来越多,越来越离不开网络,由此而产生的聊天工具越来越多,类似MSN、QQ,网络聊天时一类的聊天系统的发展日新月异,因此产生了制作一个类似QQ的网络聊天工具的想法,且经过制作该程序还能更好的学习网络软件编程知识。
网络编程的目的就是指直接或间接地经过网络协议与其它计算机进行通讯。网编程中有两个主要的问题,一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输。在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址能够唯一地确定Internet上的一台主机。而TCP层则提供面向应用的可靠的或非可靠的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据的。当前较为流行的网络编程模型是客户机/服务器(C/S)结构。即通信双方一方作为服务器等待客户提出请求并予以响应。客户则在需要服务时向服务器提出申请。服务器一般作为守护进程始终运行,监听网络端口,一旦有客户请求,就会启动一个服务进程来响应该客户,同时自己继续监听服务端口,使后来的客户也得到响应的服务。
1.2设计要求
本课程设计的目标是利用套接字socket()设计一个聊天程序,该程序基于C/S模式,客户机器向服务器发聊天请求,服务器应答并能显示客户机发过来的信息。
1.3设计目的
经过设计一个网络聊天程序,对套接字、数据报通讯、URL、与URLConnectiom的相关知识有详细的了解和充分的认识。能将相关的只是运用到相关的实践中去。
1.4功能实现
聊天室共分为客户端和服务端两部分,服务器程序主要负责侦听客户端发来的消息,客户端需要登录到相应的服务器才能够实现正常的聊天功能。
服务器的主要功能有
1) 在特定端口上进行侦听,等待客户连接
2) 用户能够配置服务器的真挺端口
3) 向已经连接服务器的客户发送系统消息
4) 统计在线人数
5) 当停止服务时,断开所有用户的连接
客户端的主要功能
1) 连接到已经开启聊天服务的服务端
2) 用户能够配置要连接服务器端的ip地址和端口号
3) 用户能够配置连接后显示的用户名
4) 当服务器开启时。用户能够随时登陆和注销
5) 用户能够向所有人或一个人发送消息
二、 总体设计
2.1设计思想
套接字对象在网络编程中扮演者重要的角色,能够用套接字技术编写一个聊天室,服务器为每个客户启动一个线程。在该线程中经过套接字和客户交流信息,当客户向服务器发送一条聊天信息“大家好”时,服务器要让所有的这些线程中的输入流写入信息大家好,这样所有的客户的套接字的输入流就都读取到了这一条信息。如果把信息“你好”发送给特定用户,服务器就让特定线程中的输出流写入信息“你好”,那么只有特定客户的套机字的输入流能够读取到这条信息。
在聊天室中需要对用户上线下线的状态进行修改,进而统计在线人数、查找某用户等。因而需要用到java链表来实现。由于Java语言不像c或c++一样能够利用线性表的链式存储结构,用节点和指针来表示,在Java中是没有指针的,可是能够经过使用对象的引用来实现链表。链表的结点个数称为链表的长度。因此在Java中能够定义两个类来实现链表的操作,分别为节点类和链表类。在本设计中对用户的存储就是利用链表来实现的。
2.2基本设计概念和处理流程
本系统运行用JAVA开发,采用C\S结构,系统分为客服端和服务端两大模块,使用Socket类建立套接字实现客服端和服务端得通讯。
处理流程
客户端
服务端
发送请求
处理请求
服务端 客户端
一个ServerSocket对象和一个Socket对象 一个Socketd对象
ServerSocket(port)创立ServerSocket对象提供TCP连接服务
Accept()
在指定端口等待客户端的连接请求
连接成功,获得一个已连接的socket对象
InputStream
读取Socket对象的输入流
OutputStream
写入Socket对象的输出流
InputStream
读取Socket对象的输入流
OutputStream
写入Socket对象的输出流
Socket(host,port)创立Socket对象,向指定主机端口发出连接请求
Socket.close()
关闭TCP连接
ServerSocket.close()
停止提供TCP连接服务
Socket.close()
关闭TCP连接
建立Socket连接
申请连接
经过流传送数据
TCP Socket通信流程
2.3总体结构
网络聊天室
服务端
客服端
2.4功能分配
客户端
向所有人或一个人发送消息
客户端
连接服务端
配置服务端
登录与注销
服务端
服务端
等待客户连接
配置服务器侦听端口
向用户发送系统消息
统计在线人数、断开连接等
2.5接口设计
2.5.1用户接口
提供一个用户操作界面:包括用户能够再界面中登录聊天室、输入消息、浏览聊天内容和聊天对象。
同时提供一个服务器操作界面,经过服务器操作界面能够修改服务器的配置,知道用户的当前状态,并能够给用户发送指定系统信息。
2.5.2内部接口
Socket(string hont ,int port );
客户端使用Socket类建立与服务器的套接字连接。
ServerSocket(int port);
建立接收客户的套接字的服务器套接字。
2.6主要模块
2.6.1聊天室服务器端模块
聊天室服务器端模块主要有以下几部分组成
1、 主框架类(ChatServer.java)
该文件包含名为ChatServer的public类,其主要功能是定义服务器的界面,添加事件侦听鱼事件处理。ChatServer类调用ServerListen类来实现服务端用户上线与下线的侦听,调用ServerReceive类来实现服务器端消息的转发。
2、 服务器用户上线与下线侦听类。
该类对用户上线与下线的侦听是经过调用用户链表类来实现的,当用户的上线与下线情况发生改变时,该类会对主类的界面进行相应的修改。
3、 服务器消息收发类
该类分别定义了向某用户及向所有人发送消息的方法,发送的消息会显示在主界面类的界面上。
4用户修改配置的类。
该类继承自JDialog。使用户对服务器端口进行修改配置的类。
5节点类
定义了链表中的用户
6链表类
该类经过构造函数构造用户链表,定义了添加用户、删除用户、返回用户数、根据用户名查找用户和各根据索引查找用户等方法。
7服务器帮助类、
2.6.2聊天室服务器端模块算法描述
ActionListener
ChatServer
-port:public static in
-serverSocket:ServerSocket
-messageShow:JTextArea
-userLinkList:UserLinkList
-showStatus:JTextField
+ ChatServer():public
+init():public void
+startService():public void
+stopService():public void
+sendStopToAll():public void
+sendMsgToAll(String):public void
+ sendSystemMessage():public void
JFrame
Thread
ServerListen
- server: ServerSocket
- userLinkList :UserLinkList
- isStop: public Boolean
+ServerListen(ServerSocket,JComboBox,JTextArea,JTextField,UserLinkList)
ServerReceive
-textarea:JTextArea
- userLinkList :UserLinkList
- isStop: public Boolean
+ServerListen(ServerSocket,JComboBox,JTextArea,JTextField,UserLinkList)
服务器端的ChatServer类继承自JFrame并实现相应的事件监听接口,因此它定义了服务器的主框架,及各个按钮的事件监听。它分别调用ServerListen类来实现服务端用户上线与下线的侦听,调用ServerReceive类来实现服务器端消息的转发。同时服务器能够响应多个客户的请求,当一个客户发送请求时,服务器就为它增加一个线程,同时服务器利用UserLinkList类为客户端设置一个请求队列,如果服务器不能马上响应客户端的请求,就要把这个请求放到请求队列在中,,等服务器将当前的请求处理完,会自动到请求队列中按照先后顺序取出请求进行处理。
2.6.3聊天室客户端模块
客户端主要有以下几个文件,功能如下:
1客户端主框架类
该类主要定义客户端的界面,添加事件侦听与事件处理。该类定义了与服务器实现连接与断开连接的方法。当用户登录到指定的服务器上时,该类条用客户端实现消息收发的类实现消息的收发。同时该类定义了向所有用户发送消息的方法。
2客户端消息收发的类
该类实现了服务器与客户端消息的收发
3用户修改配置的类
该类继承自JDialog,是用户对要连接的服务器IP及侦听端口进行修改配置的类。
4帮助类
客户端用户程序的帮助类
2.6.4聊天室客户端模块主要算法描述
ActionListener
ChatClient
-port:public static in
-serverSocket:ServerSocket
-messageShow:JTextArea
-userLinkList:UserLinkList
-showStatus:JTextField
+ ChatClient():public
+init():public void
+Connect():public void
+DisConnect():public void
+SendMessage():public void
JFrame
Thread
ClientReceive
- socket: Socket
-output:ObjectOutputStream
-input:ObjectInputStream +ClientReceive(Socket,ObjectOutputStream,ObjectIn JComboBox,JTextArea,JTextField )
客户端ChatClient类继承了JFrame并实现相应的事件监听接口。它实现了客户端的主界面及相应按钮的事件侦听。该类调用ClientReceive类实现消息的收发。同时该类定义了向所有用户发送消息的方法。经过相应的输入输出流与服务器进行数据的传递与交流。
三、 主要代码实现
3.1服务器主要代码实现
1、Chatserver类:包含名为ChatServer的public类,其主要功能为定义服务器端的界面,添加事件侦听与事件处理。调用ServerListen类来实现服务端用户上线与下线的侦听,调用ServerReceive类来实现服务器端的消息的收发。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import .*;
import java.io.*;
/*
* 聊天服务端的主框架类
*/
public class ChatServer extends JFrame implements ActionListener{
public static int port = 8888;//服务端的侦听端口
ServerSocket serverSocket;//服务端Socket
Image icon;//程序图标
JComboBox combobox;//选择发送消息的接受者
JTextArea messageShow;//服务端的信息显示
JScrollPane messageScrollPane;//信息显示的滚动条
JTextField showStatus;//显示用户连接状态
JLabel sendToLabel,messageLabel;
JTextField sysMessage;//服务端消息的发送
JButton sysMessageButton;//服务端消息的发送按钮
UserLinkList userLinkList;//用户链表
//建立菜单栏
JMenuBar jMenuBar = new JMenuBar();
//建立菜单组
JMenu serviceMenu = new JMenu ("服务(V)");
//建立菜单项
JMenuItem portItem = new JMenuItem ("端口设置(P)");
JMenuItem startItem = new JMenuItem ("启动服务(S)");
JMenuItem stopItem=new JMenuItem ("停止服务(T)");
JMenuItem exitItem=new JMenuItem ("退出(X)");
JMenu helpMenu=new JMenu ("帮助(H)");
JMenuItem helpItem=new JMenuItem ("帮助(H)");
//建立工具栏
JToolBar toolBar = new JToolBar();
//建立工具栏中的按钮组件
JButton portSet;//启动服务端侦听
JButton startServer;//启动服务端侦听
JButton stopServer;//关闭服务端侦听
JButton exitButton;//退出按钮
//框架的大小
Dimension faceSize = new Dimension(400, 600);
ServerListen listenThread;
JPanel downPanel ;
GridBagLayout girdBag;
GridBagConstraints girdBagCon;
/**
* 服务端构造函数
*/
public ChatServer(){
init();//初始化程序
//添加框架的关闭事件处理
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
//设置框架的大小
this.setSize(faceSize);
//设置运行时窗口的位置
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
this.setLocation( (int) (screenSize.width - faceSize.getWidth()) / 2,
(int) (screenSize.height - faceSize.getHeight()) / 2);
this.setResizable(false);
this.setTitle("聊天室服务端"); //设置标题
//程序图标
icon = getImage("icon.gif");
this.setIconImage(icon); //设置程序图标
show();
//为服务菜单栏设置热键'V'
serviceMenu.setMnemonic('V');
//为端口设置快捷键为ctrl+p
portItem.setMnemonic ('P');
portItem.setAccelerator (KeyStroke.getKeyStroke (KeyEvent.VK_P,InputEvent.CTRL_MASK));
//为启动服务快捷键为ctrl+s
startItem.setMnemonic ('S');
startItem.setAccelerator (KeyStroke.getKeyStroke (KeyEvent.VK_S,InputEvent.CTRL_MASK));
//为端口设置快捷键为ctrl+T
stopItem.setMnemonic ('T');
stopItem.setAccelerator (KeyStroke.getKeyStroke (KeyEvent.VK_T,InputEvent.CTRL_MASK));
//为退出设置快捷键为ctrl+x
exitItem.setMnemonic ('X');
exitItem.setAccelerator (KeyStroke.getKeyStroke (KeyEvent.VK_X,InputEvent.CTRL_MASK));
//为帮助菜单栏设置热键'H'
helpMenu.setMnemonic('H');
//为帮助设置快捷键为ctrl+p
helpItem.setMnemonic ('H');
helpItem.setAccelerator (KeyStroke.getKeyStroke (KeyEvent.VK_H,InputEvent.CTRL_MASK));
}
/**
* 程序初始化函数
*/
public void init(){
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
//添加菜单栏
serviceMenu.add (portItem);
serviceMenu.add (startItem);
serviceMenu.add (stopItem);
serviceMenu.add (exitItem);
jMenuBar.add (serviceMenu);
helpMenu.add (helpItem);
jMenuBar.add (helpMenu);
setJMenuBar (jMenuBar);
//初始化按钮
portSet = new JButton("端口设置");
startServer = new JButton("启动服务");
stopServer = new JButton("停止服务" );
exitButton = new JButton("退出" );
//将按钮添加到工具栏
toolBar.add(portSet);
toolBar.addSeparator();//添加分隔栏
toolBar.add(startServer);
toolBar.add(stopServer);
toolBar.addSeparator();//添加分隔栏
toolBar.add(exitButton);
contentPane.add(toolBar,BorderLayout.NORTH);
//初始时,令停止服务按钮不可用
stopServer.setEnabled(false);
stopItem .setEnabled(false);
//为菜单栏添加事件监听
portItem.addActionListener(this);
startItem.addActionListener(this);
stopItem.addActionListener(this);
exitItem.addActionListener(this);
helpItem.addActionListener(this);
//添加按钮的事件侦听
portSet.addActionListener(this);
startServer.addActionListener(this);
stopServer.addActionListener(this);
exitButton.addActionListener(this);
combobox = new JComboBox();
combobox.insertItemAt("所有人",0);
combobox.setSelectedIndex(0);
messageShow = new JTextArea();
messageShow.setEditable(false);
//添加滚动条
messageScrollPane = new JScrollPane(messageShow,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
messageScrollPane.setPreferredSize(new Dimension(400,400));
messageScrollPane.revalidate();
showStatus = new JTextField(35);
showStatus.setEditable(false)
sysMessage = new JTextField(24);
sysMessage.setEnabled(false);
sysMessageButton = new JButton();
sysMessageButton.setText("发送");
//添加系统消息的事件侦听
sysMessage.addActionListener(this);
sysMessageButton.addActionListener(this);
sendToLabel = new JLabel("发送至:");
messageLabel = new JLabel("发送消息:");
downPanel = new JPanel();
girdBag = new GridBagLayout();
downPanel.setLayout(girdBag);
girdBagCon = new GridBagConstraints();
girdBagCon.gridx = 0;
girdBagCon.gridy = 0;
girdBagCon.gridwidth = 3;
girdBagCon.gridheight = 2;
girdBagCon.ipadx = 5;
girdBagCon.ipady = 5;
JLabel none = new JLabel(" ");
girdBag.setConstraints(none,girdBagCon);
downPanel.add(none);
girdBagCon = new GridBagConstraints();
girdBagCon.gridx = 0;
girdBagCon.gridy = 2;
girdBagCon.insets = new Insets(1,0,0,0);
girdBagCon.ipadx = 5;
girdBagCon.ipady = 5;
girdBag.setConstraints(sendToLabel,girdBagCon);
downPanel.add(sendToLabel);
girdBagCon = new GridBagConstraints();
girdBagCon.gridx =1;
girdBagCon.gridy = 2;
girdBagCon.anchor = GridBagConstraints.LINE_START;
girdBag.setConstraints(combobox,girdBagCon);
downPanel.add(combobox);
girdBagCon = new GridBagConstraints();
girdBagCon.gridx = 0;
girdBagCon.gridy = 3;
girdBag.setConstraints(messageLabel,girdBagCon);
downPanel.add(messageLabel);
girdBagCon = new GridBagConstraints();
girdBagCon.gridx = 1;
girdBagCon.gridy = 3;
girdBag.setConstraints(sysMessage,girdBagCon);
downPanel.add(sysMessage);
girdBagCon = new GridBagConstraints();
girdBagCon.gridx = 2;
girdBagCon.gridy = 3;
girdBag.setConstraints(sysMessageButton,girdBagCon);
downPanel.add(sysMessageButton);
girdBagCon = new GridBagConstraints();
girdBagCon.gridx = 0;
girdBagCon.gridy = 4;
girdBagCon.gridwidth = 3;
girdBag.setConstraints(showStatus,girdBagCon);
downPanel.add(showStatus);
contentPane.add(messageScrollPane,BorderLayout.CENTER);
contentPane.add(downPanel,BorderLayout.SOUTH);
//关闭程序时的操作
this.addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
stopService();
System.exit(0);
}}}}
/**
* 事件处理
*/
public void actionPerformed(ActionEvent e) {
Object obj = e.getSource();
if (obj == startServer || obj == startItem) { //启动服务端
startService();
}
else if (obj == stopServer || obj == stopItem) { //停止服务端
int j=JOptionPane.showConfirmDialog(
this,"真的停止服务吗?","停止服务",
JOptionPane.YES_OPTION,JOptionPane.QUESTION_MESSAGE);
if (j == JOptionPane.YES_OPTION){
stopService();
}
}
else if (obj == portSet || obj == portItem) { //端口设置
//调出端口设置的对话框
PortConf portConf = new PortConf(this);
portConf.show();
}
else if (obj == exitButton || obj == exitItem) { //退出程序
int j=JOptionPane.showConfirmDialog(
this,"真的要退出吗?","退出",
JOptionPane.YES_OPTION,JOptionPane.QUESTION_MESSAGE);
if (j == JOptionPane.YES_OPTION){
stopService();
System.exit(0);
}
}
else if (obj == helpItem) { //菜单栏中的帮助
//调出帮助对话框
Help helpDialog = new Help(this);
helpDialog.show();
}
else if (obj == sysMessage || obj == sysMessageButton) { //发送系统消息
sendSystemMessage();
}
}
/**
* 启动服务端
*/
public void startService(){
try{
serverSocket = new ServerSocket(port,10);
messageShow.append("服务端已经启动,在"+port+"端口侦听...\n");
startServer.setEnabled(false);
startItem.setEnabled(false);
portSet.setEnabled(false);
portItem.setEnabled(false);
stopServer .setEnabled(true);
stopItem .setEnabled(true);
sysMessage.setEnabled(true);
}
catch (Exception e){
//System.out.println(e);
}
userLinkList = new UserLinkList();
listenThread = new ServerListen(serverSocket,combobox,
messageShow,showStatus,userLinkList);
listenThread.start();
}
/**
* 关闭服务端
*/
public void stopService(){
try{
//向所有人发送服务器关闭的消息
sendStopToAll();
listenThread.isStop = true;
serverSocket.close();
int count = userLinkList.getCount();
int i =0;
while( i < count){
Node node = userLinkList.findUser(i);
node.input .close();
node.output.close();
node.socket.close();
i ++;
}
stopServer .setEnabled(false);
stopItem .setEnabled(false);
startServer.setEnabled(true);
startItem.setEnabled(true);
portSet.setEnabled(true);
portItem.setEnabled(true);
sysMessage.setEnabled(false);
messageShow.append("服务端已经关闭\n");
combobox.removeAllItems();
combobox.addItem("所有人");
}
catch(Exception e){
//System.out.println(e);
}
}
/**
* 向所有人发送服务器关闭的消息
*/
public void sendStopToAll(){
int count = userLinkList.getCount();
int i = 0;
while(i < count){
Node node = userLinkList.findUser(i);
if(node == null) {
i ++;
continue;
}
try{
node.output.writeObject("服务关闭");
node.output.flush();
}
catch (Exception e){
//System.out.println("$$$"+e);
}
i++;
}
}
/**
* 向所有人发送消息
*/
public void sendMsgToAll(String msg){
int count = userLinkList.getCount();//用户总数
int i = 0;
while(i < count){
Node node = userLinkList.findUser(i);
if(node == null) {
i ++;
contin
展开阅读全文