《软件工程 课程设计 Socket聊天系统.doc》由会员分享,可在线阅读,更多相关《软件工程 课程设计 Socket聊天系统.doc(28页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、目录1.前言42.需求分析52.1系统的功能需求52.1.4点歌52.1.5分组管理52.1.6个人信息管理52.1.7用户管理52.1.8视频通话52.2非功能需求:52.2.2网络安全52.3用例分析62.3.1参与者62.3.2用例分析62.3.3系统的用例图63.总体设计83.1TCP服务器设置83.2分析类图93.3顺序图103.2.1用户私聊顺序图103.2.2用户传送文件序列图113.3协作图113.3.1用户私聊协作图113.3.2用户传送文件协作图124.详细设计144.1客户端设计144.2服务端设计144.3多线程设计155.代码实现165.1服务端设计165.2客户端设
2、计185.3多线程225.3.1服务端多线程225.3.2客户端多线程246.运行与测试256.1用户登录界面256.2输入端口界面256.3服务器记录,在线的用户信息。266.4私聊266.4.1登录266.4.2用户给指定的好友发送信息。(私聊)276.4.3指定好友接受到好友信息。(私聊的信息)276.4.5好友回复我的信息286.5群聊286.5.1发送群消息286.5.2好友响应并接受群聊信息29297. 小结308.参考文献31 1.前言 随着互联网的快速发展,网络聊天工具已经作为一种重要的信息交流工具,受到越来越多的网民的青睐。目前,出现了很多非常不错的聊天工具,其中应用比较广泛
3、的有Netmeeting、腾讯QQ、MSN-Messager等等。该系统开发主要包括一个网络聊天服务器程序与一个网络聊天客户程序两个方面。前者通过Socket套接字建立服务器,服务器能读取、转发客户端发来信息,并能刷新用户列表。后者通过与服务器建立连接,来进行客户端与客户端的信息交流。其中用到了局域网通信机制的原理,通过直接继承Thread类来建立多线程。开发中利用了计算机网络编程的基本理论知识,如TCP/IP协议、客户端/服务器端模式(Client/Server模式)、网络编程的设计方法等。在网络编程中对信息的读取、发送,是利用流来实现信息的交换,其中介绍了对实现一个系统的信息流的分析,包含
4、了一些基本的软件工程的方法。经过分析这些情况,该局域网聊天工具采用Eclipse为基本开发环境与java语言进行编写,首先可在短时间内建立系统应用原型,然后,对初始原型系统进行不断修正与改进,直到形成可行系统本文通过java的Socket实现了一个基于局域网与网络的聊天室的程序的开发-基于java的C/S模式网络聊天室的设计与实现。C/S(Client/Server)结构,即大家熟知的客户机与服务器结构。它是软件系统体系结构,通过它可以充分利用两端硬件环境的优势,将任务合理分配到Client端与Server端来实现,降低了系统的通讯开销。目前大多数应用软件系统都是Client/Server形式
5、的两层结构,由于现在的软件应用系统正在向分布式的Web应用发展,Web与Client/Server应用都可以进行同样的业务处理,应用不同的模块共享逻辑组件;因此,内部的与外部的用户都可以访问新的与现有的应用系统,通过现有应用系统中的逻辑可以扩展出新的应用系统。这也就是目前应用系统的发展方向。关键词:聊天客户端信息服务器端 Java C/S聊天系统2.需求分析2.1系统的功能需求2.1.1实现私聊(一对一):在登陆的情况下选择你要聊天的好友,进行信息的传送,实现彼此的聊天,这也是本系统最基本的功能。2.1.2群聊(一对多):可以实现一对多人的聊天。2.1.3大文件传输:在能够聊天的基础上,实现通
6、讯的多元化,进行文件的传输。是通讯双方可以选择传送对方想获得的资料。2.1.4点歌2.1.5分组管理2.1.6个人信息管理2.1.7用户管理2.1.8视频通话2.2非功能需求:2.2.1界面友好:界面易操作性,对经典的聊天程序的界面进行了学习与借鉴,模仿他们的界面与常用的操作。2.2.2网络安全加密解密为了提高传输的安全性,进行加密操作。及时在网络上被别人了窃听消息,也不能得到原始信息,防止个人重要信息与隐私信息被盗。2.3用例分析2.3.1参与者本系统显而易见的两个参与者:用户与管理员。2.3.2用例分析从上面的需求里进行抽象与提取关键信息,在确定系统边界的情况下,选择最基本的用例,然后对用
7、例进行描述与细化。使其能完全的描述系统的功能性需求。2.3.3系统的用例图通过对参与者与用例的分析,确定他们的关系(包括参与者与参与者的关系,参与者与用例的关系,用例之间的关系。)其中用例之间的关系是分析中的重点,如图私聊与群聊都有socket聊天的模块,所以可以确定的是包含关系。管理个人信息,包含了分组管理与用户信息管理,其中分组管理与用户信息管理,是个人信息管理的子集,所以应该是泛化关系。在文件传输的时候,可能会产生信息的丢失,导致信息不完整,接收方不能完整收到发送方的消息,所以导致发送方重发信息。所以这是扩展关系,因为只有在传输文件失败的时候,才能启用重传文件的模块。用户所参与的模块首先
8、应该登录,在登录系统后,可以私聊与群聊来交流信息。用户可以管理自己的信息进行修改自己的信息与管理自己的分组。为了丰富系统的功能我,我们还特意实现了点歌功,与传输文件吸引用户的眼光。3.总体设计3.1TCP服务器设置在TCP/IP协议族中,有两个互不相同的传输协议:TCP(传输控制协议)与UDP(用户数据报协议)。TCP为两台主机提供高可靠性的数据通信。它所做的工作包括把应用程序交给它的数据分成合适的小块交给下面的网络层,确认接收到的分组,设置发送最后确认分组的超时时钟等。由于运输层提供了高可靠性的端到端的通信,因此应用层可以忽略所有这些细节。而另一方面,UDP则为应用层提供一种非常简单的服务。
9、它只是把称作数据报的分组从一台主机发到另一台主机,但并不保证该数据报能到达另一端。任何必需的可靠性必须由应用层来提供。Bind()Socket()Readfrom()等待客户请求处理服务请求Sendto()Close()Socket()Bind()Sendto()Readfrom()Close() 服务请求 服务应答服务器客户机 服务器与客户机通讯流程 3.2分析类图 (系统整齐的分析类图)没有类是单独存在的,通常与别的类协作,创造比单独工作更大的语义。因此,除了捕获系统的词汇以外,还要将注意力集中到这些类是如何在一起工作的。使用类图来表达这种协作。确定你建模的机制。机制代表了部分你建模的系统
10、的一些功能与行为,这些功能与行为是一组类、接口与其他事物相互作用的结果。对于每个机制,确定类、接口与其他的参与这个协作的协作。同时确定这些事物之间的关系。 用场景来预排这些事物,沿着这条路你将发现模型中忽略的部分与定义错误的部分。确定用这些事物的内容来填充它们。对于类,开始于获得一个责任(类的职责),然后,将它转化为具体的属性与方法。3.3顺序图3.2.1用户私聊顺序图用户在进入系统前首先要输入彼此通讯的端口号,由于客户机与服务器都是本机所以不需要寻找IP地址,然后输入用户名新建一个用户,由于没有保存历史记录功能,所以每次进入系统前都需要新建一个用户。然后输入用户名与密码,在确认用户与密码。登
11、陆成功,选择在线可以聊天的好友,输入信息然后发送,达到与好友的交流。3.2.2用户传送文件序列图3.3协作图3.3.1用户私聊协作图 强调的是发送与接收消息的对象之间的组织结构。一个协作图显示了一系列的对象与在这些对象之间的联系以及对象间发送与接收的消息。对象通常是命名或匿名的类的实例,也可以代表其他事物的实例。3.3.2用户传送文件协作图用户在登录系统后,进入登陆界面,在界面的好友框里,选择要传送文件的好友,点击传送文件的按钮,会弹出选择文件的对话框,在对话框里查找你所在的文件系统中你要传送的文件。然后点击传送。4.详细设计4.1客户端设计一个网络聊天室的运行,首先是要有一个完整稳定的服务器
12、端,并且拥有很多个服务器端。客服端要具有实现用户注册与用户登陆,在登陆成功后,要显示出公聊界面,实现聊天功能并且能够发送表情与保存聊天内容与显示聊天记录等功能,在新用户上线与用户下线时要更新每个客户端在线用户列表名,并且可以与在线的用户实现一对一的私聊功能。在服务器端可以实现不断的监听客服的连接,并且根据客户端发送过来的不同信息如注册信息,登录信息,公聊信息,私聊信息,退出信息等,服务器端要做出不同的响应,并且要实现数据库的操作,如根据用户注册的信息保存数据库中,根据登录时发送来的用户名与密码检测是否合法用户等。经为每一个连接着的客户端建立了一个线程,这个线程好比一根 线一直等待客户端说话,而
13、信息发送中心就相当于一个总台,一旦有人打 进来,就通过 线把信息传完成了服务器端的第一个的任务,那么第二个任务也就不难解决了。上面已送到总台,再由总台根据需要将这个信息发送给接收群。这样就意味着,服务器每接受一条信息,就要调用一次信息发送中心的方法,并将这条信息发送到所有客户端(或者特定的某个某几个客户端)。电脑每做的一次动作,一个步骤,都是按照以经用计算机语言编好的程序来执行的,程序是计算机要执行的指令的集合,而程序全部都是用我们所掌握的语言来编写的。所以人们要控制计算机一定要通过计算机语言向计算机发出命令。侦听服务器发送的连接请求,有请求就接收发来的信息,并通过短信猫发出去单的说,服务器端
14、是为客户端服务的,服务的内容诸如向客户端提供资源,保存客户端数据等等.客户端可以是任意的一台电脑,只要它与服务器端存在连接,并且得到了服务器端的授权,就可以使用服务器端的服务.象现在就可以理解为百度的网站是服务器端,我们现在使用的电脑就是客户端.我们可以使用它的服务.4.2服务端设计由于客户端需要同时能够接收信息以及发送信息,所以也必须利用多个线程来实现。主线程用于接收用户输入的内容并将之发送到服务器端,而一个后台线程将一直接收来自服务器端的信息,并将之返回给客户端的用户。客户端(Client)或称为用户端,是指与服务器相对应,为客户提供本地服务的程序。除了一些只在本地运行的应用程序之外,一般
15、安装在普通的客户机上,需要与服务端互相配合运行。因特网发展以后,较常用的用户端包括了如万维网使用的网页浏览器,收寄电子邮件时的电子邮件客户端,以及即时通讯的客户端软件等。对于这一类应用程序,需要网络中有相应的服务器与服务程序来提供相应的服务,如数据库服务,电子邮件服务等等,这样在客户机与服务器端,需要建立特定的通信连接,来保证应用程序的正常运行。不过客户端及伺服端的关系不见得一定建立在两台分开的机器上,同一台机器中也有这种主从关系的存在。提供服务的伺服端及接受服务的客户端也有可能都在同一台机器上,例如我们在提供网页的服务器上执行浏览器浏览本机所提供的网页,这样在同一台机器上就同时扮演伺服端及客
16、户端。4.3多线程设计为了能实现一对多的通话聊天也就是说间接的多对多的聊天的功能,所以必须在客户端配置与服务端配置的时候。实现多线程的功能。实现程序的并发。以及可以减少创建进程是CPU的资源浪费。与服务区负荷太重。多线程在客户端可以实现,用户进行群聊,以及接受多个好友的响应信息。在服务端可以减少创建进程的开销。在一个程序中,这些独立运行的程序片断叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”。多线程处理一个常见的例子就是用户界面。利用线程,用户可按下一个按钮,然后程序会立即作出响应,而不是让用户等待程序完成了当前任务以后才开始响应。使用线程可以把占据时间长的程序中的任务放到
17、后台去处理用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度。程序的运行速度可能加快,在一些等待的任务实现上如用户输入、文件读写与网络收发数据等,线程就比较有用了。在这种情况下可以释放一些珍贵的资源如内存占用等等。但是如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换。更多的线程需要更多的内存空间。线程可能会给程序带来更多“bug”,因此要小心使用。线程的中止需要考虑其对程序运行的影响。通常块模型数据是在多个线程间共享的,需要防止线程死锁情况的发生。5.代码实现5.1服务端设计 public class ServerFrame
18、extends JFrame private JPanel contentPane;private JTextField txtPort;private JLabel lblState;private JTextArea txtAllUsers;/ 集合:用来保存所有登录的用户private List allLoginUser = null;public static void main(String args) EventQueue.invokeLater(new Runnable() public void run() try ServerFrame frame = new ServerF
19、rame();/ 禁止用户更改窗体的大小frame.setResizable(false);/ 距中frame.setLocationRelativeTo(null);frame.setVisible(true); catch (Exception e) e.printStackTrace();public ServerFrame() allLoginUser = new ArrayList();initComponet();public List getAllLoginUser() return allLoginUser;public void setAllLoginUser(List al
20、lLoginUser) this.allLoginUser = allLoginUser;private void initComponet() setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setBounds(100, 100, 449, 506);contentPane = new JPanel();contentPane.setBorder(new EmptyBorder(5, 5, 5, 5);setContentPane(contentPane);contentPane.setLayout(null);JPanel panel = ne
21、w JPanel();panel.setBorder(new TitledBorder(UIManager.getBorder(TitledBorder.border),u670Du52A1u5668u4FE1u606F, TitledBorder.LEADING,TitledBorder, null, new Color(0, 70, 213);panel.setBounds(10, 10, 421, 143);contentPane.add(panel);panel.setLayout(null);JLabel label = new JLabel(u670Du52A1u5668u72B6
22、u6001uFF1A);label.setBounds(48, 38, 81, 23);panel.add(label);lblState = new JLabel(New label);lblState.setBounds(161, 42, 110, 15);panel.add(lblState);JLabel label_1 = new JLabel(u670Du52A1u5668u7AEFu53E3uFF1A);label_1.setBounds(48, 87, 81, 15);panel.add(label_1);txtPort = new JTextField();txtPort.s
23、etBounds(161, 84, 110, 21);panel.add(txtPort);txtPort.setColumns(10);JButton btnStart = new JButton(u542Fu52A8u670Du52A1u5668);btnStart.addActionListener(new ActionListener() public void actionPerformed(ActionEvent e) try startServer(e); catch (IOException e1) / TODO Auto-generated catch blocke1.pri
24、ntStackTrace();btnStart.setBounds(289, 83, 93, 23);panel.add(btnStart);JPanel panel_1 = new JPanel();panel_1.setBorder(new TitledBorder(null,u5DF2u7ECFu767Bu5F55u7684u7528u6237,TitledBorder.LEADING, TitledBorder, null, null);panel_1.setBounds(20, 163, 411, 299);contentPane.add(panel_1);panel_1.setLa
25、yout(new BorderLayout(0, 0);txtAllUsers = new JTextArea();panel_1.add(txtAllUsers, BorderLayout.CENTER);public void updateGui() this.txtAllUsers.setText(null);for (int i = 0; i this.allLoginUser.size(); i+) this.txtAllUsers.append(allLoginUser.get(i).getUserName();this.txtAllUsers.append(n);protecte
26、d void startServer(ActionEvent e) throws IOException / 验证:是否为空的验证if (CommValidate.isEmpty(txtPort.getText() JOptionPane.showMessageDialog(null, 端口号不能空);return;/ 端口必须是数字if (!CommValidate.isDigit(txtPort.getText() JOptionPane.showMessageDialog(null, 端口号必须是数字);return;/ 1024之上/ 建立一个监听socketint port = In
27、teger.parseInt(txtPort.getText();ServerSocket serverSocket = new ServerSocket(port);ServerListerenThread serverListeren = new ServerListerenThread(serverSocket, this);this.lblState.setOpaque(true);this.lblState.setForeground(Color.red);this.txtPort.setEnabled(false);/ 禁用5.2客户端设计public class ClientLo
28、gin extends JFrame private JPanel contentPane;private JTextField txtLoginUser;private JTextField txtAddress;private JTextField txtPort;private Socket socket;/ 登录用户信息private UserInfo loginUser = null;public UserInfo getLoginUser() return loginUser;public void setLoginUser(UserInfo loginUser) this.log
29、inUser = loginUser;public Socket getSocket() return socket;public void setSocket(Socket socket) this.socket = socket;private ServerSocket serverSocket;public static void main(String args) EventQueue.invokeLater(new Runnable() public void run() try ClientLogin frame = new ClientLogin();frame.setAlway
30、sOnTop(true);frame.setResizable(false);frame.setVisible(true); catch (Exception e) e.printStackTrace();public ClientLogin() initComponet();private void initComponet() setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setBounds(100, 100, 397, 298);contentPane = new JPanel();contentPane.setBorder(new Emp
31、tyBorder(5, 5, 5, 5);setContentPane(contentPane);contentPane.setLayout(null);JPanel panel = new JPanel();panel.setBorder(new TitledBorder(null, u7528u6237u767Bu5F55,TitledBorder.LEADING, TitledBorder, null, null);panel.setBounds(10, 10, 369, 244);contentPane.add(panel);panel.setLayout(null);JLabel l
32、abel = new JLabel(u7528u6237u540DuFF1A);label.setBounds(37, 36, 54, 15);panel.add(label);txtLoginUser = new JTextField();txtLoginUser.setBounds(145, 33, 140, 21);panel.add(txtLoginUser);txtLoginUser.setColumns(10);JLabel label_1 = new JLabel(u670Du52A1u5668u5730u5740uFF1A);label_1.setBounds(37, 80,
33、98, 15);panel.add(label_1);txtAddress = new JTextField();txtAddress.setText(localhost);txtAddress.setBounds(145, 77, 140, 21);panel.add(txtAddress);txtAddress.setColumns(10);JLabel label_2 = new JLabel(u7AEFu53E3u53F7uFF1A);label_2.setBounds(37, 120, 54, 15);panel.add(label_2);txtPort = new JTextFie
34、ld();txtPort.setText(5555);txtPort.setBounds(145, 117, 140, 21);panel.add(txtPort);txtPort.setColumns(10);JButton btnLogin = new JButton(u767Bu5F55);btnLogin.addActionListener(new ActionListener() public void actionPerformed(ActionEvent e) try login(e); catch (UnknownHostException e1) / TODO Auto-ge
35、nerated catch blocke1.printStackTrace(); catch (IOException e2) / TODO Auto-generated catch blocke2.printStackTrace(); catch (ClassNotFoundException e3) / TODO Auto-generated catch blocke3.printStackTrace();btnLogin.setBounds(69, 164, 93, 23);panel.add(btnLogin);JButton btnReset = new JButton(u91CDu
36、7F6E);btnReset.setBounds(192, 164, 93, 23);panel.add(btnReset);protected void login(ActionEvent e) throws IOException,ClassNotFoundException / 验证/ 得到GUI界面上的数据String userName = this.txtLoginUser.getText();String serverAddress = this.txtAddress.getText();int serverPort = Integer.parseInt(this.txtPort.
37、getText();NormalClass.serverAddress = serverAddress;NormalClass.sererPort = serverPort;/ 创建一个登录用户String clientIP = NormalClass.splitIp(InetAddress.getLocalHost().toString();int clientPort = NormalClass.randomPort();loginUser = new UserInfo(userName, null, clientIP, clientPort);loginUser.setImageInde
38、x(int) (Math.random() * 10);/ 向服务器建立一个连接: 请求Socket socket = new Socket(serverAddress, serverPort);/ 发送数据:构建一个数据包DataPacket dataPacket = new DataPacket(ICommands.LOGIN, loginUser,null, new Date(), null);OutputStream out = socket.getOutputStream();ObjectOutputStream objOut = new ObjectOutputStream(out
39、);objOut.writeObject(dataPacket);/ 等待服务器的响应InputStream in = socket.getInputStream();ObjectInputStream objIn = new ObjectInputStream(in);dataPacket = (DataPacket) objIn.readObject();if (dataPacket.getCommand().equals(ICommands.LOGIN_SUCCESS) ClientChat chat = new ClientChat(this);chat.setTitle(this.l
40、oginUser.getUserName() + 登录了);chat.setVisible(true);this.setVisible(false);objIn.close();objOut.close();socket.close();5.3多线程5.3.1服务端多线程public ServerChatThread(Socket socket, ServerFrame frame) this.socket = socket;this.frame = frame;this.start();public void run() / 接收用户传过来的数据包try inputStream = this
41、.socket.getInputStream();objIn = new ObjectInputStream(inputStream);DataPacket dataPacket = (DataPacket) this.objIn.readObject();/ 用户要干 什么?String command = dataPacket.getCommand();if (command.equals(ICommands.LOGIN) / 表示用户要登录UserInfo loginUser = dataPacket.getFromUserInfo();/ 身份验证 (略)保存用户的唯一性/ 保存登录的
42、用户this.frame.getAllLoginUser().add(loginUser);/ 更新用户的最新信息this.frame.updateGui();/ 发送一个信息过去dataPacket.setCommand(ICommands.LOGIN_SUCCESS);dataPacket.setFromUserInfo(null);dataPacket.setToUserInfo(loginUser);this.outPutStream = this.socket.getOutputStream();this.objOut = new ObjectOutputStream(this.ou
43、tPutStream);this.objOut.writeObject(dataPacket);/ 向每个登录的用户发送最新的登录用户的集合sendAllUserInfo(); else if (command.equals(ICommands.CLOSE_CLIENT_WINDOW) / 用户要关闭了UserInfo unLoginUser = dataPacket.getFromUserInfo();this.frame.getAllLoginUser().remove(unLoginUser);this.frame.updateGui();/ 给客户dataPacket.setCommand(ICommands.CLOSE_CLIENT_WINDOW_SUCCESS);this.outPutStream = this.socket.getOutputStream();this.objOut = new ObjectOutputStream(this.outPutStream);this.objOut.writeObject(dataPacket);/ 把最新的信息告诉客户sendAllUserInfo(); catch (IOException e) / TODO Auto-g
限制150内