聊天室系统设计报告.doc

上传人:牧羊曲112 文档编号:4296431 上传时间:2023-04-14 格式:DOC 页数:52 大小:2.45MB
返回 下载 相关 举报
聊天室系统设计报告.doc_第1页
第1页 / 共52页
聊天室系统设计报告.doc_第2页
第2页 / 共52页
聊天室系统设计报告.doc_第3页
第3页 / 共52页
聊天室系统设计报告.doc_第4页
第4页 / 共52页
聊天室系统设计报告.doc_第5页
第5页 / 共52页
点击查看更多>>
资源描述

《聊天室系统设计报告.doc》由会员分享,可在线阅读,更多相关《聊天室系统设计报告.doc(52页珍藏版)》请在三一办公上搜索。

1、聊天室系统设计报告青 岛 科 技 大 学操 作 系 统 课 程 设 计学生班级 计算机132班 学生学号 1308010204 学生姓名 王永远 518 182016_年 _月 _日设计题目:聊天室系统一、设计目的及要求 1.1设计目的通过该聊天室系统,掌握网络编程的概念及基于网络的C/S模式软件系统开发,掌握基于TCP协议的Socket编程,掌握Java的多线程机制。1.2设计要求:实现多个用户之间类似于QQ的聊天程序,有聊天界面,多用户之间既可以实现群聊,也可以单独聊天。二、技术背景2.1网络编程就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换。2.2网络通信(1)IP地址:

2、网络中设备的标识,不易记忆,可用主机名要想让网络中的计算机能够互相通信,必须为每台计算机指定一个标识号,通过这个标识号来指定要接受数据的计算机和识别发送的计算机,在TCP/IP协议中,这个标识号就是IP地址。(2)端口号:用于标识进程的逻辑地址物理端口 网卡口逻辑端口 我们指的就是逻辑端口A:每个网络程序都会至少有一个逻辑端口B:用于标识进程的逻辑地址,不同进程的标识C:有效端口:065535,其中01024系统使用或保留端口。(3)传输协议:通信的规则,常见的有UDP,TCPUDP:将数据源和目的封装成数据包中,不需要建立连接;每个数据报的大小在限制在64k;因无连接,是不可靠协议;不需要建

3、立连接,速度快。TCP:建立连接,形成传输数据的通道;在连接中进行大数据量传输;通过三次握手完成连接,是可靠协议;必须建立连接,效率会稍低。2.3 Socket(1)Socket套接字网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。(2)Socket原理机制A:通信的两端都有Socket。B:网络通信其实就是Socket间的通信。C:数据在两个Socket间通过IO传输。2.4 TCP传输(1)客户端思路A建立客户端的Socket服务,并明确要连接的服务器。B如果连接建立成功,就表明,已经建立了数据传输的通道.就可以在该通道通过IO进行数据的读取和写入.该通道称

4、为Socket流,Socket流中既有读取流,也有写入流.C通过Socket对象的方法,可以获取这两个流D通过流的对象可以对数据进行传输E如果传输数据完毕,关闭资源(2)服务器端思路A建立服务器端的socket服务,需要一个端口B服务端没有直接流的操作,而是通过accept方法获取客户端对象,在通过获取到的客户端对象的流和客户端进行通信C通过客户端的获取流对象的方法,读取数据或者写入数据D如果服务完成,需要关闭客户端,然后关闭服务器,但是,一般会关闭客户端,不会关闭服务器,因为服务端是一直提供服务的2.5 Java的多线程机制进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会

5、有较大的开销,一个进程包含1-n个线程。线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。多进程是指操作系统能同时运行多个任务(程序),多线程是指在同一程序中有多个顺序流在执行。在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,启动JVM实际上就是在操作系统中启动了一个进程。在java中所有的线程都是同时启动的,至于什么时候,哪个先执行,完全看谁先得到CPU的资源。三、需求分析实现聊天的功能,采用JavaSocket编程,服务器与客户端采用了TCP

6、/IP连接方式,在设计聊天方案时,可将所有信息发往服务器端,再由服务器进行处理,服务器端是所有信息的中心。3.1客户端3.1.1登录用户需要填写用户名、服务器地址、端口号才可以进入聊天室与在线用户聊天,此外,服务器地址默认是本机地址,端口号默认是5000。用户名可以中文,英文字母或标点符号,服务器地址必须是符合点分十进制的合法地址,端口号可以修改,但服务器端程序内默认端口号也必须修改。该聊天室不需要注册,直接登录即可聊天,退出后,系统不保留用户任何信息。若新登录用户与在线用户的用户名重名,则系统会自动修改用户名。格式为:用户名+“_客户端线程ID”。3.1.2多人聊天每个在线用户都可以发送聊天

7、信息,服务器端会一直监听,并把每一个在线用户发送的聊天信息转发到每一个客户端。聊天室的聊天信息格式为:用户名 时间(yyyy-MM-dd HH:mm:ss)聊天信息3.1.3单人聊天用户可以选择某一个在线用户实现单人聊天,该聊天信息不会在聊天室显示,只有单聊的两个人能够看到。单人聊天的聊天信息格式为:用户名 时间(yyyy-MM-dd HH:mm)聊天信息3.2服务器端服务器端主要处理客户端的请求,包括用户的登录,发送多人聊天信息,退出聊天室,单人聊天请求,发送单人聊天信息,并且随时更新在线用户列表。四、总体设计4.1设计思想流程图4.2设计思想分析首先启动服务器,它会建立一个专门用于接收客户

8、端连接请求的“倾听Socket”,然后等待客户的连接请求。当用户登录输入信息后,与服务器建立Socket连接,服务器端的“倾听Socket”收到连接请求后,会接受连接请求,并生成一个服务器端socket,专门负责与此客户端socket的通信。一旦连接请求成功,客户端将信息及请求通过本方socket的输出流发送给服务器端相应的socket,服务端则通过服务器端Socket的输入流接受客户端传输过来的信息及请求,分析是何请求,然后根据请求类型,进行相应的处理(如登录、私聊等)。服务器端也可以根据需要,通过socket的输出流发送信息和请求给客户端。客户端和服务器端都可以通过关闭本方的socket而

9、结束一次通信过程。对于客户端的各种请求,实际上都是通过在客户端发往服务器的各种字符流区分的,具体的方法就是在消息的内部添加特殊字符串,从而实现服务器对消息请求的识别。比如对于登陆信息,消息中添加的内容就是“login”,而对于私聊中的消息,消息中添加的内容就是“single”,其他的同理都添加了相应内容。当然,对于客户端来说,这些都是透明的,用户的操作并没有受到任何影响。在服务器端,消息被检测分析后,变回根据具体的目的进行处理,比如是私聊消息,服务器便会根据其内部添加的信息,向目标端转发该条消息,当目标端接收到连接请求后,会主动建立一个私聊窗口,从而实现私聊。服务器端需要能同时接受多个用户的请

10、求,为了实现这一点,一般使用多线程机制来处理,对每一个客户端连接通信,服务器端都有一个线程专门负责处理。对于客户端的各种请求,内部添加的信息分别如下:l clientThread客户端线程启动 messages.add(clientThread.getId() + clientThread);客户端线程IDl login登录客户端 username+login+getThreadID()+login用户名+客户端线程IDl userlist用户列表 serverThread.users.get(new Integer(threadID) + userlist+threadID + userli

11、st用户名+客户端线程ID l chat群聊 username + chat + getThreadID() + chat+ mess + chat用户名+客户端线程ID+聊天信息l serverexit服务器退出 serverThread.messages+serverexitl single单聊 client.username + single + client.getThreadID() + single +(int)client.clientuserid.get(index) + single + mess + single;用户名+客户端线程ID+客户端线程ID+聊天信息l exit

12、退出群聊 username + exit + getThreadID() + exit用户名+客户端线程ID五、详细设计5.1客户端设计5.1.1登录界面5.1.2聊天室界面5.1.3单人聊天界面5.2服务器端设计六、系统测试6.1登录测试6.1.1用户名为英文字母6.1.2用户名为中文6.1.3用户名为标点符号6.1.4多个用户有重名6.1.5服务器地址不合法6.1.6端口号不合法6.1.7服务器未开启6.2群发消息测试6.3私聊测试6.4用户列表显示测试无论已经登录用户的退出,还是新用户成功登录,用户列表显示部分都能正确显示。七、心得体会这段时间通过不断的修改,我终于把聊天室系统完成了,虽

13、然它只有简单的聊天功能,但通过它,我不但巩固了以前学的知识,而且学到了许多在课堂中学不到的知识。通过这次课程设计,我更坚定了理论与实际相结合是十分重要的想法,即使一个人读了再多的技术图书,但没有相关的实践经验,那么他也不会真正地掌握一门技术。只有把理论知识与实践相结合,才会深入的了解并提高自己的独立思考能力。通过这次的课程设计,我将自己所学的Java语言得到了实际的应用,在完成的过程中也遇到了许多困难,但通过不断地查阅资料,最终还是解决了,在这个过程中,我学会了独立思考,同时也让我明白完成一件事情要不断开阔视野,拓展知识面,解放自己的思维。总之,在完成课程设计的过程中,我学会了如何克服开发中遇

14、到的技术困难,学会了独立面对并解决问题。八、参考资料叶核亚 JAVA程序设计实用教程(第2版)电子工业出版社朱福喜,路迟 JAVA语言与面向对象程序设计 武汉大学出版社沈文炎 Java高级编程 机械工业出版社九、程序清单(1)Client.javapublic class Client extends Threadpublic Socket c_socket ;/套接字private Client_chatFrame c_chatFrame;/聊天室聊天界面private Client_enterFrame c_enterFrame;/客户端登录界面private Client_singleF

15、rame c_singleFrame;/单人聊天界面public DataInputStream dis = null;/IO输入public DataOutputStream dos = null;/IO输出private boolean flag_exit = false;/客户端未启动标记private int threadID;/聊天室客户端线程标记public Map c_singleFrames;/单人聊天,用户名为键,单聊客户端为值public List username_online;/在线用户public List clientuserid;/用户IDpublic Strin

16、g username = null;/用户名public String chat_re;/通道内相关信息/getter, setter方法public Client_chatFrame getC_chatFrame() return c_chatFrame;public Client_singleFrame getC_singlFrame() return c_singleFrame;public void setC_singlFrame(Client_singleFrame c_singlFrame) this.c_singleFrame = c_singlFrame;public void

17、 setC_chatFrame(Client_chatFrame c_chatFrame) this.c_chatFrame = c_chatFrame;public Client_enterFrame getC_enterFrame() return c_enterFrame;public void setC_enterFrame(Client_enterFrame c_enterFrame) this.c_enterFrame = c_enterFrame;public int getThreadID() return threadID;public void setThreadID(in

18、t threadID) this.threadID = threadID;/客户端构造函数public Client()c_singleFrames = new HashMap();username_online = new ArrayList();clientuserid = new ArrayList();/signlechatuse = new ArrayList();/main方法,设置进入时登录界面public static void main(String args) Client client = new Client();Client_enterFrame c_enterFra

19、me = new Client_enterFrame(client);client.setC_enterFrame(c_enterFrame);c_enterFrame.setVisible(true);/登录客户端public String login(String username, String hostIp, String hostPort) this.username = username;/用户名String login_mess = null;/错误信息或truetry c_socket = new Socket(hostIp, Integer.parseInt(hostPort

20、); catch (NumberFormatException e) login_mess = 连接的服务器端口号port为整数,取值范围为:1024port sSize.height)wSize.height = sSize.height;if(wSize.width sSize.width)wSize.width = sSize.width;win.setLocation(sSize.width - wSize.width)/ 2, (sSize.height - wSize.height)/ 2);/窗体居屏幕中央(3)Server.javapublic class Server pri

21、vate ServerFrame serverFrame;private ServerThread serverThread;public ServerFrame getServerFrame() return serverFrame;public void setServerFrame(ServerFrame serverFrame) this.serverFrame = serverFrame;public Server()/启动服务器线程public void startServer() tryserverThread = new ServerThread(serverFrame);ca

22、tch(Exception e)System.exit(0);serverThread.setFlag_exit(true);serverThread.start();/停止服务器线程public void stopServer()synchronized (serverThread.messages) /同步代码块:synchronized:当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。String str = serverexit;serverThread.messages.add(str);serverThread.serverFrame.se

23、tDisMess(exit);/清除聊天信息serverThread.serverFrame.setDisUsers(exit);/清除在线用户serverThread.stopServer();/停止服务器线程/main方法public static void main(String args) Server server = new Server();ServerFrame serverFrame = new ServerFrame(server);server.setServerFrame(serverFrame);serverFrame.setVisible(true);/停止服务器线

24、程并退出public void close() if(serverThread != null)if(serverThread.isAlive()serverThread.stopServer();System.exit(0);(4)ServerThread.javapublic class ServerThread extends Thread /Vector类可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。/但是,Vector 的大小可以根据需要增大或缩小,以适应创建 Vector 后进行添加或移除项的操作。 public ServerSocket server

25、Socket;/服务器套接字public Vector messages;/messages.add(clientThread.getId() + clientThread)public Vector clients;/客户端线程public Map users;/客户端线程ID和用户姓名public BroadCast broadcast;public int Port = 5000;public boolean login = true;public ServerFrame serverFrame;private boolean flag_exit = false;/服务器未启动publi

26、c ServerThread(ServerFrame serverFrame)this.serverFrame = serverFrame;messages = new Vector();clients = new Vector();users = new HashMap();try serverSocket = new ServerSocket(Port); catch (IOException e) this.serverFrame.setStartAndStopUnable();System.exit(0);broadcast = new BroadCast(this);broadcas

27、t.setFlag_exit(true);broadcast.start();/启动广播线程Overridepublic void run() Socket socket;while(flag_exit)try if(serverSocket.isClosed()flag_exit = false;elsetrysocket = serverSocket.accept();/接收客户端请求,无请求则阻塞catch(SocketException e)socket = null;flag_exit = false;if(socket != null)ClientThread clientThre

28、ad = new ClientThread(socket, this);clientThread.setFlag_exit(true);clientThread.start();/启动客户端线程/* * synchronized:当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。 * 同步代码块 线程同步(目的是为了保护多个线程访问一个资源时对资源的破坏) */synchronized (clients) /客户端线程clients.addElement(clientThread);synchronized (messages) users.put(in

29、t) clientThread.getId(), login);messages.add(clientThread.getId() + clientThread); catch (IOException e) e.printStackTrace();/停止服务器public void stopServer() try if(this.isAlive()serverSocket.close();setFlag_exit(false); catch (Throwable e) /设置服务器启动标志public void setFlag_exit(boolean b) flag_exit = b;(

30、5)ClientThread.javapublic class ClientThread extends Thread public Socket clientSocket;/客户端套接字public ServerThread serverThread;public DataInputStream dis;public DataOutputStream dos;/public String client_userID;private boolean flag_exit = false;/客户端线程启动标记public ClientThread(Socket socket, ServerThre

31、ad serverThread)clientSocket = socket;this.serverThread = serverThread;try dis = new DataInputStream(clientSocket.getInputStream();dos = new DataOutputStream(clientSocket.getOutputStream(); catch (IOException e) e.printStackTrace();Overridepublic void run() while(flag_exit)try /从通道读出信息String Message

32、 = dis.readUTF();if(Message.contains(login)/有新登录用户String userInfo = Message.split(login);int userID = Integer.parseInt(userInfo1);serverThread.users.remove(userID);if(serverThread.users.containsValue(userInfo0)/新登录的与原来的有重名for(int i = 0; i serverThread.clients.size(); i+)int id = (int)serverThread.cl

33、ients.get(i).getId();if(serverThread.users.get(id).equals(userInfo0)/用户名相同serverThread.users.remove(id);serverThread.users.put(id, userInfo0 + _ + id);/额外添加标记(线程ID),更新新登录的用户break;serverThread.users.put(Integer.parseInt(userInfo1), userInfo0 + _ + userInfo1);/更新原来用户elseserverThread.users.put(userID,

34、userInfo0);/更新服务器端用户列表Message = null;StringBuffer sb = new StringBuffer();synchronized (serverThread.clients) /同步代码块:客户线程for(int i = 0; i serverThread.clients.size(); i+)int threadID = (int) serverThread.clients.elementAt(i).getId();/客户线程IDsb.append(String)serverThread.users.get(new Integer(threadID) + userlist);/用户姓名+“userlist” sb.append(threadID + userlist);/用户姓名+“

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号