1、Java 通信程序设计课程设计报告题 目 Java 网络聊天室程序设计学生姓名 学 号 院 系 电子与信息工程学院专 业 通信工程2013 年 12 月Java网络聊天室程序设计翟轶彪,20121334080南京信息工程大学通信工程系,南京 210044摘要:随着网络信息时代的来临,Internet 应用越来越广泛 人们越来越习惯于在网上获取和交流信息。据调查显示,80%以上的人上网都会打开聊天工具来聊天,而几乎每一个年轻人都会去聊天。使用网上聊天已经成为现代年轻人一种新的交往方式。聊天室更适合于陌生人之间进行较为主观、感兴化的讨论。所以有大部分的人会进入聊天室聊天 它会给人一个完全自由的聊天
2、世界。因此我们联系所学的知识做一个简易的聊天室系统。关键词:网上聊天;聊天室1、背景知识1.SOCKETSocket可以看成在两个程序进行通讯连接中的一个端点,是连接应用程序和网络驱动程序的桥梁,Socket 在应用程序中创建,通过绑定与网络驱动建立关系。此后,应用程序送给 Socket的数据,由 Socket交网络驱动程序向网络上发送出去。计算机从网络上收到与该 Socket绑定 IP地址和端口号相关的数据后,由网络驱动程序交给 Socket,应用程序便可从该 Socket中提取接收到得数据,网络应用程序就是这样通过 Socket进行数据的发送与接收的。1.1 创建 Socket;1.2 打
3、开连接到 Socket的输入/出流;1.3 按照一定的协议对 Socket进行读/写操作;1.4 关闭 Socket.2.IO技术2.1阻塞模式2.2可能造成阻塞的函数有:connect()、accept()、读写函数3.C/S两端通过 Socket机制进行连接3.1客户端的编程流程:3.1.1创建 Socket对象,向 Server的监听端口请求;3.1.2通过向新 Socket中读写数据与 Server端通信;3.1.3关闭 Socket,结束与 Server端;3.2服务器端的编程流程:3.2.1打开 Server Socket,创建一个服务器型套接字和一个普通套接字,服务器型套接字在指
4、定端口为客户端请求的 Socket 服务;3.2.2等待来自客户端的 Client端的请求;3.2.3接收 Client端的请求,用返回的 Socket建立连接;3.2.4通过向 Socket中读写数据来与 Client端通信;3.2.5关闭 Socket,结束与当前 Client端的通信;3.2.6关闭 SerketSocket对象结束监听服务。2、设计思想用户客户端服务器端用户设置连接设置用户发送信息通信内容用户得到的信息处理用户退出服务器日志 数据通信信息连接保存保存处理监控1.客户端设计思想客户端主要完成建立连接、消息输入、消息发送、消息存储功能。功能含义如下:1.1建立连接:建立一个
5、 ServerSocket连接,不断侦听是否有服务端连接或者断开连接。1.2消息输入:根据用户输入的消息,将消息显示在屏幕面板上。1.3消息发送:把用户输入的消息作为字符串通过 Socket端口发送到服务器。1.4消息存储:把用户输入的消息存储到 data.txt文件中,以便用户以后查阅聊天记录。2.客户端设计2.1界面设计2.2连接设计2.3接收信息设计2.4用户信息设计2.5帮助设计3.客户端连接服务器端客户端用户设计的 IP地址和端口号连接到相应的服务器,通过接收用户输入的消息,然后通过所监听的端口把消息发送到服务端,由服务端把消息发送到指定的用户。3.1客户端请求连接客户端通过 con
6、nect()请求连接,填写端口号以及 IP地址,填写自己的信息。3.2服务器端响应服务器端的监听器监听到客户端的连接请求后,检测后允许客户端连接到服务器。3.3给客户端返回信息连接成功后服务器返回给客户端连接成功的信息,并且给所有的用户发送用户登录信息。3.4关闭 Socket连接当以上的程序都正常运行后,需要关闭 Socket连接,否则将会浪费服务器与客户端之间的资源。3.5用户退出3.5.1接收退出信息当用户退出时,客户端将会用基于 Socket的对象输出流发送给服务器退出对象。3.5.2在线列表中删除用户用户退出后应该把用户从在线列表中删除,否则用户退出用户还在在线列表中,那么该用户下次
7、将会无法登录。3.5.3更新在线列表用户退出后将服务器端监控界面的用户列表更新。否则用户数据将会不同步。4.服务器设计思想主服务器类实现了服务器端的多线程,使用 SeverSocket s=newServerSocket(8080)语句在 8080端口创建套接口;使用 new ServerThread(socket)语句创建新的线程。主服务器类调用 ServerThread类,而每个 ServerThread实体就是一个独立的线程,刚好对应于客户端的连接请求响应线程。服务器端有一个(或多个)进程在指定的端口等待客户的连接信息,一旦连接成功,就可以按设计的数据交换方法和格式进行数据传输。服务器端
8、完成的功能是:对服务器的某一可用端口进行监听,以获得客户端请求,从而对客户端请求进行处理。因为是多客户同时请求,所以要采用多线程,为每一个在线用户分配一个线程,实时处理每个客户端的请求。因此,对服务器端程序抽象如下:4.1公共数据处理 处理公共数据。如在线人数统计,客户的公共数据(如通知等) ,客户数据资料的存储与读取等(与数据库交互) ;4.2端口监听器监听服务器某一端口,为每一在线客户建立一个会话线程;4.3客户请求处理 处理客户的请求。根据客户的请求执行相应的操作。4.4服务器管理器服务器端的管理工具,如对数据进行统计。客户端服务器端用户发送信息通信内容用户得到的信息处理用户退出服务器日
9、志 数据通信信息连接保存保存处理监控服务器设置3、主要代码1.客户端主要代码/* 事件处理*/public void actionPerformed(ActionEvent e) Object obj = e.getSource();if (obj = userItem | obj = userButton) /用户信息设置/调出用户信息设置对话框UserConf userConf = new UserConf(this,userName);userConf.setVisible(true);userName = userConf.userInputName;else if (obj = co
10、nnectItem | obj = connectButton) /连接服务端设置/调出连接设置对话框ConnectConf conConf = new ConnectConf(this,ip,port);conConf.setVisible(true);ip = conConf.userInputIp;port = conConf.userInputPort;else if (obj = loginItem | obj = loginButton) /登录Connect();else if (obj = logoffItem | obj = logoffButton) /注销DisConne
11、ct();showStatus.setText(“);else if(obj = dataItem)tryFile read=new File(“data.txt“);Desktop.getDesktop().open(read);catch (IOException e1)e1.printStackTrace();else if (obj = clientMessage | obj = clientMessageButton) /发送消息SendMessage();clientMessage.setText(“);else if (obj = exitButton | obj = exitI
12、tem) /退出int j=JOptionPane.showConfirmDialog(this,“真的要退出吗?“,“退出“,JOptionPane.YES_OPTION,JOptionPane.QUESTION_MESSAGE);if (j = JOptionPane.YES_OPTION)if(type = 1)DisConnect();System.exit(0);else if (obj = helpItem) /菜单栏中的帮助/调出帮助对话框Help helpDialog = new Help(this);helpDialog.setVisible(true);public voi
13、d run()while(!socket.isClosed()tryString type = (String)input.readObject();if(type.equalsIgnoreCase(“系统信息“)String sysmsg = (String)input.readObject();SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss“); String ly_time = sdf.format(new Date();textarea.append(ly_time);textarea.append(“n
14、“);textarea.append(“系统信息: “+sysmsg);else if(type.equalsIgnoreCase(“服务关闭“)output.close();input.close();socket.close();textarea.append(“服务器已关闭!n“);break;else if(type.equalsIgnoreCase(“聊天信息“)String message = (String)input.readObject();SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss“);
15、String ly_time = sdf.format(new Date();textarea.append(ly_time);textarea.append(“n“);textarea.append(message);tryrecord=new BufferedWriter(new FileWriter(“data.txt“,true);record.write(ly_time);record.newLine();record.write(message);record.newLine();record.close();catch (IOException e)e.printStackTra
16、ce();else if(type.equalsIgnoreCase(“用户列表“)String userlist = (String)input.readObject();String usernames = userlist.split(“n“);combobox.removeAllItems();int i =0;combobox.addItem(“所有人“);while(i usernames.length)combobox.addItem(usernamesi);i +;combobox.setSelectedIndex(0);showStatus.setText(“在线用户 “ +
17、 usernames.length + “ 人“);catch (Exception e )System.out.println(e);2.服务器端主要代码2.1 ChatServer.java 服务器的主框架类此类实现接口 ActionListener,用于对用户事件的监听,以及对事件的处理。/* 事件处理*/public void actionPerformed(ActionEvent e)Object obj = e.getSource();if (obj = startServer | obj = startItem) / 启动服务端startService(); else if (o
18、bj = 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
19、);portConf.setVisible(true); 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) / 菜单栏中的帮助/ 调出帮助对话框Hel
20、p helpDialog = new Help(this);helpDialog.setVisible(true); else if (obj = sysMessage | obj = sysMessageButton) / 发送系统消息sendSystemMessage(); /* 此函数用于启动服务器,并在指定的端口监听客户端的连接*/public void startService()tryserverSocket = new ServerSocket(port, 10);messageShow.append(“服务端已经启动,在“ + port + “端口侦听.n“);startSer
21、ver.setEnabled(false);startItem.setEnabled(false);portSet.setEnabled(false);portItem.setEnabled(false);stopServer.setEnabled(true);stopItem.setEnabled(true);sysMessage.setEnabled(true); catch (Exception e)e.printStackTrace();userLinkList = new UserLinkList();listenThread = new ServerListen(serverSoc
22、ket, combobox, messageShow,showStatus, userLinkList);listenThread.start();/* 此函数用于关闭服务器,关闭服务器后给所有在线用户发送服务器关闭的信息,服 * 务器关闭后,所有的input,output输入输出流都会关闭,并且socket也会关闭。* 所有的数据都恢复初始化*/public void stopService()try/ 向所有人发送服务器关闭的消息sendStopToAll();listenThread.isStop = true;serverSocket.close();int count = userL
23、inkList.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(
24、true);sysMessage.setEnabled(false);messageShow.append(“服务端已经关闭n“);combobox.removeAllItems();combobox.addItem(“所有人“); catch (Exception e)e.printStackTrace();2.2 ServerListen.java 服务端的侦听类此类继承于 Thread类,服务器的监听类,等待用户的连接,并且给在线用户发送上线用户的信息提示。public void run()while(!isStop client.socket = server.accept();cli
25、ent.output = new ObjectOutputStream(client.socket.getOutputStream();client.output.flush();client.input = new ObjectInputStream(client.socket.getInputStream();client.username = (String)client.input.readObject();/显示提示信息combobox.addItem(client.username);userLinkList.addUser(client);SimpleDateFormat sdf
26、 = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss“); String str = sdf.format(new Date();textarea.append(str + “n“ + “用户 “ + client.username + “ 上线“ + “n“);textfield.setText(“在线用户“ + userLinkList.getCount() + “人n“);recvThread = new ServerReceive(textarea,textfield,combobox,client,userLinkList);recvThread.
27、start();catch(Exception e)2.3 ServerReceive.java服务器收发消息的类此类也继承于 Thread 类,主要处理客户端发来的信息,并对信息进行必要的处理,通过 input 输入流以及 output 输出流把信息输出在指定用户的对话框中。除此之外还对用户下线时作必要的处理,提示用户下线,以及显示在线人数。public void run()/向所有人发送用户的列表sendUserList();while(!isStop if(type.equalsIgnoreCase(“聊天信息“)String toSomebody = (String)client.in
28、put.readObject();String status = (String)client.input.readObject();String action = (String)client.input.readObject();String message = (String)client.input.readObject();String msg = client.username +“ “+ action+ “对 “+ toSomebody + “ 说 : “+ message + “n“;if(status.equalsIgnoreCase(“悄悄话“)msg = “ 悄悄话 “
29、+ msg;SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss“); String str = sdf.format(new Date(); textarea.append(str + “n“ + msg);if(toSomebody.equalsIgnoreCase(“所有人“)sendToAll(msg);/向所有人发送消息elsetryclient.output.writeObject(“聊天信息“);client.output.flush();client.output.writeObject(msg);cl
30、ient.output.flush();catch (Exception e)/System.out.println(“#“+e);Node node = userLinkList.findUser(toSomebody);if(node != null)node.output.writeObject(“聊天信息“); node.output.flush();node.output.writeObject(msg);node.output.flush();else if(type.equalsIgnoreCase(“用户下线“)Node node = userLinkList.findUser
31、(client.username);userLinkList.delUser(node);String msg = “用户 “ + client.username + “ 下线n“;int count = userLinkList.getCount();combobox.removeAllItems();combobox.addItem(“所有人“);int i = 0;while(i count)node = userLinkList.findUser(i);if(node = null) i +;continue; combobox.addItem(node.username);i+;co
32、mbobox.setSelectedIndex(0);SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss“); String str = sdf.format(new Date(); textarea.append(str + “n“ + msg);textfield.setText(“在线用户“ + userLinkList.getCount() + “人n“);sendToAll(msg);/向所有人发送消息sendUserList();/重新发送用户列表,刷新break;catch (Exception e)/System.out.println(e);4、调试与测试经调试后程序无误。参考文献1 张孝祥 Java 就业培训教程 清华大学出版社2003376-382