《java实现聊天系统.docx》由会员分享,可在线阅读,更多相关《java实现聊天系统.docx(28页珍藏版)》请在三一办公上搜索。
1、计算机网络课程设计报告学生姓名学号班 级指导教师设计时间目录13第一章系统描述1.1设计目的 1.2系统设计任务 1.3系统设计分析 1.4系统功能分析第二章功能模块结构2.1模块划分 2.2模块结构图 2.1模块功能第三章模块算法实现3.1服务器实现 3.2客户端实现第四章运行结果第五章课程设计总结171919第六章附录6.1参考文献6.2源代码第一章系统描述1.1设计目的1. 学习网络编程的知识,掌握网络编程的方法。2. 进一步掌握编程思想与编程技巧,做到模块化程序设计,3. 强化语言学习,尤其是Java的图形界面与多线程,需反复练习,熟练掌 握。1.2系统设计任务聊天室软件的设计与开发:
2、基本要求可以完成群聊、私人聊天,实时发送和 显示聊天信息,完成好友列表;进一步要求带表情,附件发送,聊天信息的加密 传送,设置黑名单等。学习通信编程Socket接口编程,使用TCP或UDP接口完成信息传送,利用 多线程技术实现服务器端的多个TCP连接的建立。1.3系统设计分析一.实现网络聊天室编程,关键在于Socket通信,程序的功能都是在Socket 的基础上一层一层增加的。实现Socket通信的基本方法为以下4个步骤。(1) 在客户端与服务器端创建相应的ServerSockot/Socket实例。(2) 打开连接到Socket的输入输出流(3) 利用输入输出流,按照一定的协议(TCP协议)
3、对Socket进行读写 操作(4) 关闭输入输出流和Socket我们要实现的功能都是在第3步对Socket的输入输出流做相应的操作二.因为是多客户端,所以必须用线程进行控制,不同的处理线程为不同的客 户服务,主线程只负责循环等待,处理线程负责网络连接,接受客户输入的信息, 再做相应的处理。1.4系统功能分析本系统可以通过网络进行聊天,采用客户端服务器模式,所以程序简介 清晰易懂,而且用户都是在客户端进行活动,方便对用户的管理,也使得程 序运行与差错简单起来。采用了多线程技术,可以做到多人同时在线,提高 了系统的性能,增强了系统的实用性。有简单的客户端界面,方便用户使用。 采用的是TCP协议,这
4、是可靠的,稳定的协议,这样不会丢失任何包,也就 不会丢失任何信息。本系统实现的功能有:1. 用户名字登录2. 用户之间的群聊3. 用户之间的私聊4. 动态刷新并显示好友列表5. 显示在线人数6. 服务器可以显示用户在线状态7. 能够退出处理8. 用户上下线提醒第二章功能模块结构2.1模块划分服务器:Server 类模块,ServerHanderson 模块,sendallclient 模块,sendclientlist模块客户端:Client类模块,ServiceFrame窗口界面模块2.3模块功能服务器:1. Server类模块:与客户端建立连接,通过套接字获得名字,在控制端 显示提示信息2
5、. ServerHander模块:提供线程管理,实现多用户的管理。针对每一个 用户发过来的消息,进行相应处理,再转发给客户。3. Sendallclient模块:给每个用户发送消息。4. Sendclientlist模块:每当有用户上线,更新每个用户的用户列表。 客户端:1. Client类模块:与服务端建立连接,用户登录,实现消息的群聊,私聊, 用户列表的更新等功能。2. ServiceFrame窗口界面模块:客户端窗口界面,实现用户友好,方便用 户使用,在窗口上有消息显示,用户列表,在线人数等视图信息。第三章模块算法实现3.1服务器实现L Server类模块:创建ServerSocket,
6、在指定端口监听,当有用户登录, 接受套接字输入流,显示其登录信息,调用ServerHander线程进行管理。 public Server(int port) throws IOExceptionServerSocket server=new ServerSocket(port);while(true)(Socket conn=server.accept();/接收客户端套接字DataInputStream in =new DataInputStream(conn.getInputStream();String who=in.readUTF();System.out.print(Client+(
7、ip:+conn.getInetAddress()+)+who+ 进入! + n);ServerHander cn=new ServerHander(who,conn);cn.start();2- Sendallclient模块: 把msg消息发送给每一个用户。其中allclients是 ServerHander的枚举类型,可以指向每一个用户。protected static void sendallclient(String msg)(synchronized (clientlist)Enumeration allclients= clientlist.elements();while(al
8、lclients.hasMoreElements()ServerHander serh=(ServerHander)allclients.nextElement();tryserh.out.writeUTF(msg);serh.out.flush();catch(IOException exc)serh.interrupt();3-Sendclientlist模块:更新用户列表,当有新用户上线时,对以前的用户的好 友列表,加上这个新用户名字,对于这个新用户,加上所有用户的名字。实现方 法是在名字信息后面加上“ $”关键字,这样客户端接收到这个关键字时,做相 应处理。 public static
9、 synchronized void sendclientlist()( for(int j=0;jclientlist.size();j+) ServerHander allclients1=clientlist.elementAt(j); if (j=clientlist .size()-1)/若是新增用户,把v ector中的所有用户都发送过去 for(int i = 0;iclientlist.size();i+) ServerHander allclients2=clientlist.elementAt(i); try( allclients1.out.writeUTF(allcli
10、ents2. who+$); allclients1.out.flush(); catch(IOException exc)( allclients1.interrupt(); else 老用户,只增加新来的用户 ServerHander allclients3=clientlist.lastElement(); try allclients1.out.writeUTF(allclients3. who+$); allclients1.out.flush(); catch(IOException exc) allclients1.interrupt(); 4-ServerHander模块:关键
11、模块,与客户端进行消息的交互,相互加关键字, 解密关键字,做到上下线提醒,群聊,私聊等功能。创建ServerHander的Vector 对象,可以方便用户管理,Vector对象是可变数组,而且支持线程同步,适合在网络编程中使用。对用户发送过来的消息通过关键字进行解析,前面的字符 串为发送的消息,后面的字符串为发送对象,若发送给所有人,则直接发送,若 发送给某个人,则在发送的消息后面再加上关键字,让客户端去解析。有用户 下线,发送下线消息,通过下线关键字,可以在客户端更新用户列表。class ServerHander extends ThreadSocket socket;DataInputSt
12、ream in;DataOutputStream out;String who;protected static VectorcLientList=newVector() ; /把用户线程放入可变对象数组public ServerHander(String name,Socket socket) throws IOException( this.who = name;this.socket = socket;in =new DataInputStream(newBufferedInputStream(socket.getInputStream();out =new DataOutputStre
13、am(newBufferedOutputStream(socket.getOutputStream();public void run()(try(cLientList .addElement(this);/VECTOR中增加新线程sendaLLcLient (who+”上线);sendcLientList ();为每一个客户端更新在线用户while(true)(String msg=in.readUTF();int index = msg.lastIndexOf(伊);/对客户端发过来的信息做相应的处理String str = msg.substring(index+1,msg.length
14、(); /取得发送对象和发送的消息msg=msg.substring(0,index);if (str.equals(所有人)=false)sendaLLcLient(who+对+str+说:+msg+伊);/不是发给所有人则增添标记elsesendaLLcLient(who+ 对所有人 说: +msg);catch(lOException e)( System.out.println(error); finally clientlist.removeElement(this); System.out.print(Client +(ip:+socket.getInetAddress() + )
15、+who+退出! + n); sendallclient (who+ 下线);try( socket.close(); catch(IOException ex)( System.out.println(clsing); 3.2客户端实现1-ServerFrame窗口界面模块:有一个消息显示文本区域,消息发送框, 发送按钮,好友列表下拉框,一条标签用来显示在线人数,文本区域添加在 JscrollPane上,这样,无论消息有多长,多宽,都能显示出来,如果没添加的话, 消息一多,就显示不出了,这个小细节,很多人都没注意。class ServiceFrame extends Frame( JText
16、Area showAT; JTextField sendFD; JComboBox friendlist; JButton but; JLabel showCount; JScrollPane textAreaScrollPane; JPanel textFieldPanel = new JPanel();public ServiceFrame (String winname)( super(winname);继承父类的名字setSize(500,400); textFieldPanel.setLayout(new FlowLayout(0,10,10); showAT = new JText
17、Area(400,400); showAT.setEditable(false); textAreaScrollPane = new JScrollPane(showAT);add(textAreaScrollPane, BorderLayout.CENTER);add(textFieldPanel, BorderLayout.SOUTH);friendlist = new JComboBox();friendlist .addItem(所有人);textFieldPanel.add(friendlist);sendFD = new JTextField(20);textFieldPanel.
18、add(sendFD);but = new JButton(发送);but .setMnemonic(KeyEvent. VK_ENTER);textFieldPanel.add(but);showCount = new JLabel(在线人数:1);textFieldPanel.add(showCount);show();按钮监听事件:当按下按钮,把发送文本框的消息再加上当前选择的发送对 象写入输出流,中间用关键字隔开,在服务端方便解析。class ActListener implements ActionListenerClient client;ServiceFrame sframe;p
19、ublic ActListener(Client c,ServiceFrame sf)(client=c;sframe=sf;public void actionPerformed(ActionEvent e)( 发送信息,并以作为私聊标记 client.send(sframe.sendFD.getText().trim()+sframe.friendlist.getSelecte dItem();sframe.sendFD.setText();退出事件:添加退出功能,不然直接点叉叉退出,会报错。class ExitListener extends WindowAdapterClient cl
20、ient;public ExitListener(Client c)client=c;public void windowClosing(WindowEvent e)client.close();System.exit(0);2- Client类模块:关键模块,通过服务器IP地址与端口建立连接,在控制台输入 名字,发送给服务器,服务器会进行上线提醒与更新用户列表的操作。public class Client public ServiceFrame sf;private Socket csocket;private DataInputStream in; private DataOutputSt
21、ream out;public static void main(String args)BufferedReader in = new BufferedReader(new InputStreamReader(System. in); System out .println(请输入一个名字:); String who;trywho=in.readLine().trim();控制台获得名字 catch(IOException e) e.printStackTrace();new Client(who,”127.0.0.1”,9992); 在Client的构造函数中实现对服务器消息的解析,接受消
22、息strl1. 若strl以$结尾,说明是有用户上线,在所有用户消息区域显示该消息,并且更新每一个用户的好友列表。2. 若strl以结尾,说明这是一条私聊消息,解析其中的名字信息,若该用户的名字在里面,才显示该消息。3. 若strl以下线结尾,说明有用户下线,在所有用户消息区域显示该消息,并在所有用户的用户列表中删除该用户的信息最后,显示当前在线人数。public Client(String who,String server, int port) sf=new ServiceFrame(who+的客户端);String str1 = null;sf.but.addActionListener
23、(new ActListener(this,sf); sf.addWindowListener(new ExitListener(this);trycsocket =new Socket(server,port); in=new DataInputStream(newBufferedInputStream(csocket.getInputStream();out=new DataOutputStream(newBufferedOutputStream(csocket.getOutputStream();out.writeUTF(who);out.flush();名字发给服务器while(tru
24、e)(str1 = in.readUTF();重点! !,服务器端发来的消息if(str1.endsWith($”) 若以$结尾,则增添用户 int index = str1.lastIndexOf($);String str2 = str1.substring(0,index);sf.friendlist.addItem(str2.trim();else if (str1.endsWith()以结尾为私聊信息str1=str1.substring(0,str1.length()-1);if(str1.contains(who)sf.showAT.append(- +str1+n);elsei
25、f (str1.endsWith(下线”)用户下线,删除此用户int index = str1.lastIndexOf(下线);String str2 = str1.substring(0,index);sf.friendlist.removeItem(str2.trim();sf.showAT.append(- +str1+n);sf.showCount.setText(在线人数: + (sf.friendlist.getItemCount()-1); /动态更新在线人数catch(Exception e)(System.out.println(Server Error);this.clos
26、e();System.exit(0);第四章运行结果1.服务器控制台显示并记录登录,退出信息。Server Java ApplicaticnJ U:Program hle-edipse Client(ip:/127.0-0.Clierrthp;,U孔矶队 j爻三进a!1)0 j&!Client(ip /127-0-0.errorClient (ip: /127.0.ft,!errorClient tip: /127.0.&.!2. 在客户端控制台输入名字进入聊天室。Cli&nt Java Application D:Pro-gram Files翔入一T时: 宁真Ch ent J ava App
27、li cation D:Progra m Fi 胃鞍入f君孚:3. 聊天界面显示客户端名字,好友列表,在线人数等信息。4. 私聊,群聊显示,若选择所有人则为群聊,选择某一个人,则为私聊。如下图,群聊消息,在所有客户端都显示,私聊信息只会在发送者与接受者中显 示。李四囹宁翔的客户诙|111言宁翔上线-花三上线李四上线-王五上线一赵六上线一瑟六下螃-王五下线宁翔对所有人诅:大家好,我是宁翔一宁翔对张三 说:张三,你好宁翔对李四说:李四,你好发谖 在级人孰:3图张三的睿户箕|亘|亘|j-张三上共-李四上线-王五上共-邈六上共-迅六下线-王五下线-宁翔对苗有人 说:大家好,我是宁翔-宁翔对张三说:吐三
28、,你好4III所有人 发谖在泓数3图李四的客户端|三|亘|亘-李四上线-王五上线-瑟六上线一赵六下线-王五下线-宁翔对所有人 讽:大家好,我是宁翔-宁翔对李四说;李四,你好所有人发送在荻人我45. 人数动态刷新。图宁翔的客户遂-宁翔上线-张三上线-李四上线-王五上线一赵六上线-赵六下线-王五下线-宁翔对所有人讽:大家好,我是宁翔-宁翔对器三说张三,你蚪-宁翔对李四讽:李四,你蜂白客上线W4 III李四在域人敦:A.鸟I宁翔的客户造口 II回II爰-宁翔-张三一李四-干玉上上上上S .一*.!.W-J瑟瑟王翔翔喜春四宁宁白白季说:大家好,我是宁翔说:张三,你好说;李四,你好六六五如三发送第五章课
29、程设计总结从收到题目的茫然无措,不知从何下手,到最后交出的成果,真的让我 学到了很多,可能比一学期的JAVA和网络课程设计中学到的关于TCP协议的 知识还要多,所以很感谢这次课程设计,有效果也很有意义,某种程度上比上课 效果还好。说说完成课程设计的整个过程吧。刚看到可以选择的六个题目时,犹如 晴天霹雳,别说用代码实现了,连题目要求都不理解,上课恍惚听老师提到过这 个知识点,可是重要的内容却一点也不知道,而且,由于要做图形界面,所以用 JAVA会更简单点,但JAVA也忘得差不多了,所以只能从头来过,刚开始的3 周,一点有关课程设计的代码都没写,拿着一本从零开始学JAVA把JAVA 基础知识,尤其
30、是关于网络编程,线程,图形界面的知识,狠狠地补了一把,终 于更看懂一些程序结构清晰,没有反射,泛型等高端用法的程序了。在这过程中 发现,做一个普通的网络聊天室,似乎不要用太多网络知识,懂得Socokt和TCP 的使用即可,于是开始慢慢敲代码了。先把服务器与客户端搭建起来,只能实现连接上的作用,但什么功能都 没有,那时,以为能连接上了,那实现一些私聊,群聊的功能应该很简单,但现 实确是,只能脑中想象,真的用代码实现,却总是错误百出,做的心灰意冷,尤 其是私聊功能的实现,刚开始,想让服务器直接向接受者与发送者发送消息,但 总是不如人意,折腾了大概一星期,才意识到TCP协议就是用自己定义的一些 规则
31、,在服务器与客户端之间传递消息,可以添加关键字,再解析。于是才解决 私聊问题,然后添加好友列表与更新好友的功能也在跌跌撞撞中实现了。窗口的 布局,刚开始想用网格包布局,但用的很不熟练,导致布局不理想,无奈,只能 用最基本的布局了,所以界面看上去很普通。想发送图片,却发现文本区域根本 不能显示图片,能用JEditorPane实现,但有BUG,不知如何调试,书上,网上 也没找到能解决的办法,只能放弃了。课程设计在这种不断学习与摸索中差不多完成了,说说这次课程设计的 不足吧。1. 学过的知识不牢固,所以花费了大量时间用来学习基础知识,那些应该在以前就掌握的。2. 程序界面很普通,像老师说的一样,是最
32、最古老的聊天系统,没有什么花哨。3. 没能实现附加功能,像加密传输,文件传送等功能。其实,挺遗憾的,因为以前选修过密码学,应该能够实现简单的DES加密的。4. 没有用到JDBC,把用户信息存储到数据库表中,实行账号密码登录,提高系统的安全性。做了这么多的课程设计,最大的体会就是用心去做,用心去学,你一定能 学到很多知识,而且这是对学过的知识的应用,所以比单一的上课更有意思。对于自己能独立的完成课程设计,还是颇为满意的,至少努力没有白费, 学到的知识也非常多,最重要的应该是理解了 TCP协议的原理,并学会了简单 的应用,JAVA编程水平得到了一定的提高,面向对象的思想比以往更清晰了。第六章附录6
33、.1参考文献从零开始学JAVA王发波中国铁道出版社Java 2实用教程耿祥文 清华大学出版社6.2源代码服务器代码:package service;import java.io.*;import java.util.*;import .*;public class Server public Server(int port) throws IOException ServerSocket server=new ServerSocket(port);while(true)Socket conn=server.accept(); /建立客户端套接字DataInputStream in =new D
34、ataInputStream(conn.getInputStream();String who=in.readUTF();System.out.print(Client+(ip:+conn.getInetAddress() + )+who+进入! + n);ServerHander cn=new ServerHander(who,conn); cn.start();public static void main(String args)throws IOException new Server(9992); class ServerHander extends ThreadSocket soc
35、ket;DataInputStream in;DataOutputStream out;String who;protected static VectorcLientList=new Vector() ; /把用户线程放入可变对象数组 public ServerHander(String name,Socket socket) throws IOException( this.who = name;this.socket = socket; in =new DataInputStream(new BufferedInputStream(socket.getInputStream(); out
36、 =new DataOutputStream(new BufferedOutputStream(socket.getOutputStream(); public void run()( try( cLientList .addElement(this);/VECTOR中增加新线程sendaLLcLient (who+”上线);sendcLientList ();为每一个客户端更新在线用户while(true)( String msg=in.readUTF(); int index = msg.lastIndexOf(伊);/对客户端发过来的信息做相应的处理String str = msg.su
37、bstring(index+1,msg.length();/取得发送对象和发送的消息msg=msg.substring(0,index);if (str.equals(所有人)=false) sendaLLcLient(who+ 对+str+ 说:+msg+伊);/不是发 给所有人则增添标记 elsesendaLLcLient (who+对所有人说:+msg); catch(IOException e)( System.out.println(error);finallycLientList.removeElement(this);System.out.print(Client +(ip:+s
38、ocket.getInetAddress() + )+who+退出! + n); sendaLLcLient (who+ 下线);try(socket.close();catch(lOException ex)(System.out.println(clsing);发送消息给所有用户protected static void sendallclient(String msg)( synchronized (clientlist)Enumeration allclients= clientlist.elements();while(allclients.hasMoreElements() Ser
39、verHander serh=(ServerHander)allclients.nextElement();tryserh.out.writeUTF(msg);serh.out.flush();catch(IOException exc) serh.interrupt();更新用户列表public static synchronized void sendclientlist()(for(int j=0;jclientlist.size();j+)ServerHander allclients1=clientlist.elementAt(j);if (j=clientlist .size()-
40、1)/若是新增用户,把v ector中的所有用户都发送过去for(int i = 0;iclientlist.size();i+)ServerHander allclients2=clientlist.elementAt(i);tryallclients1.out.writeUTF(allclients2. who+$);allclients1.out.flush();catch(IOException exc)allclients1.interrupt();else 老用户,只增加新来的用户ServerHander allclients3=clientlist.lastElement();t
41、ryallclients1.out.writeUTF(allclients3. who+$);allclients1.out.flush();catch(IOException exc)allclients1.interrupt();客户端代码:package service;import java.io.*;import .*;import java.awt.*;import java.awt.event.*;import javax.swing.*;public class Client public ServiceFrame sf;private Socket csocket;priva
42、te DataInputStream in; private DataOutputStream out;public static void main(String args)BufferedReader in = new BufferedReader(new InputStreamReader(System. in); System out .println(请输入一个名字:); String who;trywho=in.readLine().trim();控制台获得名字 catch(IOException e)e.printStackTrace();new Client(who,”127.
43、0.0.1”,9992);public Client(String who,String server,int port)(sf=new ServiceFrame(who+的客户端);String str1 = null;sf.but.addActionListener(new ActListener(this,sf);sf.addWindowListener(new ExitListener(this);try(csocket =new Socket(server,port);in=new DataInputStream(newBufferedInputStream(csocket.getI
44、nputStream();out=new DataOutputStream(newBufferedOutputStream(csocket.getOutputStream();out.writeUTF(who);out.flush();名字发给服务器while(true)(str1 = in.readUTF();重点! !,服务器端发来的消息if(str1.endsWith($”) 若以$结尾,则增添用户 int index = str1.lastIndexOf($);String str2 = str1.substring(0,index);sf.friendlist.addItem(str2.trim();else if (str1.endsWith()以结尾为私聊信息str