socket聊天系统的实现.doc_第1页
socket聊天系统的实现.doc_第2页
socket聊天系统的实现.doc_第3页
socket聊天系统的实现.doc_第4页
socket聊天系统的实现.doc_第5页
已阅读5页,还剩28页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

3. 程序结构简介ChatDialogl类:聊天对话框类,用来处理单聊界面,实现了一对一聊天,且会自动侦测窗口是否存在。ChatMessageDialog类:窗口弹出消息类,用来显示各种提示消息,模态对话框。DB_Controler类:数据库管理类,所有与数据库有关的操作都包装到这个类中了。FriendTree类:朋友树类,提供类似树形结构的管理方式来管理在线好友。LoginDialog类:登陆对话框类。NewChatClient类:客户端类,用来与服务器建立连接,以及用来与服务器端通信。NewChatServer类:服务器类,用来监听端口,建立与连接客户端的连接,管理并为客户端提供各种通信服务。RegistDialog类:注册对话框类,用来提供注册服务。Scaner类:文件浏览类,用来浏览文件并取出路径信息,为日志文件输出提供路径。本例子程序采用虽然采用来数据库来管理登陆信息,注册信息,用户个人信息,但程序主体还是采用TCP套接字的方式来建立网络通讯,NewChatClient,NewChatServer类就是用来建立并管理连接资源的类,由于才TCP方式,server端采用死循环来对8888端口进行监听,没有客户端建立连接,就把该客户端放入的容器中(一对一容器,和一对多容器),然后开启服务线程,为客户端提供不同的通信服务。不论客户端还是服务端多处采用多线程用来提高响应及服务速度。所以服务器端肯定会在大用户的情况下出现反应迟缓,后期服务器端会加入线程池技术来提供更多更好的连接数。由于作者水平有限,虽运用了面向对象的思想来设计本例子程序,但还是有不合思想的地方后期会再度重构,达到高耦合低内聚的设计目标,以期方便后期加入更多功能。再有客户端服务器端的通信协议在后文代码中体现不在此赘述,协议均采用明文格式,后期会加强改为加密格式,提高网络安全性。程序主要部分流程图Server端服务线程流程图:有消息无消息监听来自客户端的消息客户端有信息发过来吗还连接着bconnected?Bconnected=trueBconnected=false关闭服务线程根据连接信息初始化服务线程是给服务的消息吗显示在消息框中取出发送内容是给某个端口的消息吗是登陆的消息吗是注册的消息吗提交给注册模块处理提交给登陆模块处理根据端口转发给对方YesYesYesYesNoNoNoNo有链接监听本机上8888端口 开始服务器等待客户端连接交给服务线程处理无连接还开着吗Started?结束 关闭服务器Started=trueStarted=falseServer端主线线程的流程图:客户端流程图:退出开始通过Scoket建立TCP连接交给服务线程,处理接受消息是否按下或回车监听回车键和发送按钮通过套接字发送文本框内容退出没?没有按下按下没有退出退出客户端服务线程:初始化服务线程监听来自服务器Scocket端的消息有消息吗?在Textarea中显示消息结束还接收吗?bconnected没有有Bconnexted=falseBconnexted=true4.软件编码和调试由于本次试验只在于练习并熟悉TCP的连接方式,所以代码只附上NewChatClient和NewChatServer其他与连接不重要部分不在报告中体现。NewChatServer:/一种布局管理器用来组织用户界面的import java.awt.BorderLayout;/事件响应的事件类import java.awt.event.ActionEvent;/事件监听类import java.awt.event.ActionListener;/一种实现了窗口接口的抽象类 import java.awt.event.WindowAdapter;/窗口的事件类import java.awt.event.WindowEvent;/数据输入流类 用来对传入数据进行输入的管道import java.io.DataInputStream;/数据输出流 用来对传出数据进行输出的管道import java.io.DataOutputStream;/IO的异常处理类import java.io.IOException;/对端口地址绑定的异常处理import .BindException;/TCP中的服务器端的Socketimport .ServerSocket;/TCP中客户端的Socket本类中用于保存客户端的链接对象import .Socket;/包装Socket链接中的各种异常import .SocketException;/日期格式 处理的类import java.text.DateFormat;/日期类import java.util.Date;/哈希图容器类用来存储K-V映射关系的类import java.util.HashMap;/连接表容器类 本例用来存储所有链接到服务器端的Socketimport java.util.LinkedList;/链表类,一种容器类import java.util.List;/图类,一种容器类import java.util.Map;/一种图形组件类,按键类import javax.swing.JButton;/一种图形组件类,窗口类import javax.swing.JFrame;/一种图形组件类,标签类import javax.swing.JLabel;/一种图形组件类,菜单类import javax.swing.JMenu;/一种图形组件类,菜单条类import javax.swing.JMenuBar;/一种图形组件类,菜单项类import javax.swing.JMenuItem;/一种图形组件类,一种图形组件容器类import javax.swing.JPanel;/一种图形组件类,滑动条类import javax.swing.JScrollPane;/一种图形组件类,多行文本类import javax.swing.JTextArea;/一种图形组件类,文本编辑类import javax.swing.JTextField;/一种用户界面管理类 用来对UI整体布局进行调整的管理类import javax.swing.UIManager;/一种异常处理类,处理UI皮肤异常的import javax.swing.UnsupportedLookAndFeelException;public class NewChatServer extends JFrame /构成用户界面的全局变量 有容器类和各种组件类JTextArea jta = new JTextArea();JTextField jtf_Port = new JTextField(5);JTextField jtf_Session = new JTextField(12);JButton jb = new JButton(发送);JLabel jl_Port = new JLabel(端口号:);JLabel jl_Session = new JLabel(内容:);/服务器端的Socket用来监听一个服务器端的端口ServerSocket ss = null;/用来标识启动信息,通过它来控制boolean started = false;/boolean result = false;/用来标识从密码验证后的反馈结果boolean result = true;/时间类用来先提取当前系统时间private Date now = null;/处理时间格式的对象private DateFormat df = DateFormat.getDateTimeInstance();/容器类对象用来存储链接上服务器的客户端对象,用来实现点对点聊天Map clients_CtoC = new HashMap();/容器类对象用来存储链接上服务器的客户端对象,用来实现群聊天List clients_StoC = new LinkedList();/用来存储生成的在线端口字符串,后用来向客户端传递String online = null;/数据库控制类 所有与数据有关的操作都包装在这个类中DB_Controler dbc = new DB_Controler(this);public static void main(String args) /用户界面的启动方法new NewChatServer().launchFrame();/用来美化界面的代码段 通过UI管理器来实现try UIManager.setLookAndFeel(com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel);/ UIManager.setLookAndFeel(com.sun.java.swing.plaf.windows.WindowsLookAndFeel); catch (ClassNotFoundException e) / TODO Auto-generated catch blocke.printStackTrace(); catch (InstantiationException e) / TODO Auto-generated catch blocke.printStackTrace(); catch (IllegalAccessException e) / TODO Auto-generated catch blocke.printStackTrace(); catch (UnsupportedLookAndFeelException e) / TODO Auto-generated catch blocke.printStackTrace();public void launchFrame() /链接数据库的方法dbc.openLink();this.setLocation(30, 20);this.setSize(400, 500);jta.setEditable(false);jtf_Port.setText(all);this.add(new JScrollPane(jta), BorderLayout.CENTER);JPanel j_s = new JPanel();/ j_s.setLayout(new BorderLayout();j_s.add(jl_Port);j_s.add(jtf_Port);j_s.add(jl_Session);j_s.add(jtf_Session);j_s.add(jb);this.add(j_s, BorderLayout.SOUTH);JMenuBar jmb = new JMenuBar();JMenu jm1 = new JMenu(查看);JMenu jm2 = new JMenu(服务器动作);JMenu jm3 = new JMenu(关于);JMenuItem jmi11 = new JMenuItem(查端口号);JMenuItem jmi12 = new JMenuItem(查看在线);JMenuItem jmi13 = new JMenuItem(导出日志);JMenuItem jmi21 = new JMenuItem(运行);JMenuItem jmi22 = new JMenuItem(停机);JMenuItem jmi31 = new JMenuItem(版本);jm1.add(jmi11);jm1.add(jmi12);jm1.add(jmi13);jm2.add(jmi21);jm2.add(jmi22);jm3.add(jmi31);jmb.add(jm1);jmb.add(jm2);jmb.add(jm3);this.setJMenuBar(jmb);/为对话框的内容添加事件监听jtf_Session.addActionListener(new TextFieldListener();/为发送按钮添加事件监听jb.addActionListener(new ActionListener() public void actionPerformed(ActionEvent arg0) action(););/为查看菜单项添加事件监听jmi12.addActionListener(new ActionListener() public void actionPerformed(ActionEvent e) jta.append(online + n););/为导出日志的菜单项添加事件监听jmi13.addActionListener(new ActionListener() public void actionPerformed(ActionEvent e) appendLog(););/为开机菜单项添加事件监听jmi21.addActionListener(new ActionListener() public void actionPerformed(ActionEvent arg0) new Thread(new StartThread().start(););/ 开机动作/为关机菜单项添加事件监听jmi22.addActionListener(new ActionListener() public void actionPerformed(ActionEvent arg0) try ss.close(); catch (NullPointerException e) / / TODO Auto-generated catch block/ e.printStackTrace();jta.append(getCurrentTime() + 服务器未启动,请先启动! + n); catch (IOException e) / TODO Auto-generated catch blocke.printStackTrace(););/ 停机动作/纯属娱乐jmi31.addActionListener(new ActionListener() public void actionPerformed(ActionEvent e) new ChatMessageDialog(NewChatServer.this, 版本, 版本号:beta0.1,本程序作者:D.W&ZYX););this.setTitle(NewChatServer);/添加窗口关闭的事件监听this.addWindowListener(new WindowAdapter() public void windowClosing(WindowEvent e) dbc.setAllOfflineState();dbc.closeLink();System.exit(0););this.setResizable(false);this.setVisible(true);/创建浏览模态对话框的方法protected void appendLog() new Scaner(this);public void action() String str_Port = jtf_Port.getText().trim();String str_Session = jtf_Session.getText().trim();/从容器中提取出需要发送信息且已经建立链接的对象Client c = clients_CtoC.get(str_Port);/协议的格式如果发送的端口号位all则从容器中提取出每一个已建立链接的客户端对象发送系统的消息if (str_Port.equalsIgnoreCase(all) for (int i = 0; i + jtf_Port.getText() + n);/协议格式-系统-:*c.TCPSend(-系统-: + str_Session);/如果所写的端口号不是已经存在的则提示端口号有误 else jta.append(端口号有误请检查!n);jtf_Session.setText();jtf_Port.setText(all);/启动方法public void start() if (!started) started = true;try /如果没有存在则打开8888端口进行监听if (ss = null)ss = new ServerSocket(8888); catch (BindException e) /对于端口已经绑定的异常处理,警告提示等待五秒退出this.setVisible(false);new ChatMessageDialog(this, 警告, 端口地址已经占用, 请调换TCP端口地址!);try Thread.sleep(5000); catch (InterruptedException e1) e1.printStackTrace();System.exit(0); catch (IOException e) e.printStackTrace();/服务启动完成提示信息jta.append(getCurrentTime() + 服务器启动完成,正在运作.! + n);/用来等待客户端链接的代码段while (started) try /如果接受到某个客户端Socket的链接则把连接信息包装到一个客户端类中统一管理Socket s = ss.accept();Client c = new Client(s);String key = s.getPort() + ;/用一个包装好的客户端来启动一个客户端服务进程new Thread(c).start();/把包装好的连接放到两个容器中进行统一管理clients_CtoC.put(key, c);/ 单聊clients_StoC.add(c);/ 群聊jta.append(getCurrentTime() + s.getInetAddress() + /+ s.getPort() + 客户端连接上本服务器 + n);/显示在线客户端数jta.append(剩余在线客户端数: + clients_CtoC.size() + n);/一下代码段生成在线客户端端口号的字符串String str_Online = 当前在线#;for (int i = 0; i clients_StoC.size(); i+) / best/ MethodClient ct = clients_StoC.get(i);str_Online += ct;str_Online += #;/ 生成在线名单/发送生成的在线客户端字符串online = str_Online;for (int i = 0; i = 3) /如果拆开后长度超过3则划分为协议头,端口号,和内容String str_protocal = str_splits0;String str_Port = str_splits1;String str_Session = str_splits2;String str_fromPort = s.getPort() + ;/如果协议头是送给服务器的则打印到服务器端的现实栏if (str_Port.trim().equalsIgnoreCase(Server) jta.append(s.getPort() + : + str + n);/如果协议头是验证密码的则分离出账号和密码送给数据库进行查询else if (str_protocal.trim().equalsIgnoreCase(Password) String account = str_splits1;String password = str_splits2;/通过DB控制类来获得验证反馈结果result = dbc.checkPassword(account, password);Client c = clients_CtoC.get(str_fromPort);/根据查询的返回结果发送不同的验证结果给客户端if (result) c.TCPSend(密码验证#密码正确#);dbc.updateOnlineState(account, this.c_Port); else c.TCPSend(密码验证#密码错误,+ dbc.getVerifyErrorInfo() + #); /如果协议头是注册账号则分离各种注册信息送给数据库控制程序进行处理else if (str_protocal.trim().equalsIgnoreCase(Regist) System.out.println(str_splits1: + str_splits1);System.out.println(str_splits2: + str_splits2);String account = str_splits1;String password = str_splits2;/通过DB控制类来获得注册反馈结果boolean result = dbc.registAccount(account, password);Client c = clients_CtoC.get(str_fromPort);/根据数据库反馈注册的注册消息发送不同的注册结果给客户端if (result) c.TCPSend(注册反馈#注册成功#); else c.TCPSend(注册反馈#注册失败#+ dbc.getRegistErrorInfo() + #); /如果端口号是已经存在的则通过端口号发送给已经连接上的相应的客户端else if (clients_CtoC.containsKey(str_Port) Client c = clients_CtoC.get(str_Port);c.TCPSend(str_fromPort + : + str_Session);jta.append(str_fromPort + - + str_Port + n); /如果端口号有误的处理else jta.append(str_fromPort + 发来的端口号有误!n);Client c = clients_CtoC.get(str_fromPort);c.TCPSend(-系统-送达方端口号有误,请检查!); catch (NullPointerException e) /用来处理客户端下线的处理过程/从两个容器类中删除下线的客户端clients_StoC.remove(this);clients_CtoC.remove(this.s.getPort() + );/在服务器端打印在线客户端信息jta.append(剩余在线客户端数: + clients_CtoC.size() + n);/更新数据库中的在线客户端信息dbc.updateOfflineState(this.c_Port);/更新每个在线客户端的其他在线客户端信息String str_Online = 当前在线#;for (int i = 0; i clients_StoC.size(); i+) / best MethodClient ct = clients_StoC.get(i);str_Online += ct;str_Online += #;/ 生成在线名单online = str_Online;for (int i = 0; i clients_StoC.size(); i+) / best MethodClient ct = clients_StoC.get(i);ct.TCPSend(str_Online);/ 按在线名单发送/服务器的关闭处理关闭各种打开的资源public void close() if (running) running = false;try if (ss != null) ss.close();ss = null;if (s != null) s.close();s = null;if (dos = null)dos.close();if (dis = null)dis.close(); catch (IOException e) e.printStackTrace();jta.append(getCurrentTime() + 服务器已经停机! + n); else jta.append(getCurrentTime() + 服务器已经停机!请勿重复操作! + n);/通过TCP方式发送信息public void TCPSend(String str) if (s != null)try dos.writeUTF(str);dos.flush(); catch (SocketException e) clients_StoC.remove(this);clients_CtoC.remove(this.s.getPort() + );jta.append(丄条消息未发出,端口号 + this.s.getPort() + 客户端已经断线!n); catch (IOException e) e.printStackTrace();/通过TCP方式接受信息public String TCPReceive() String str = null;try str = dis.readUTF(); catch (IOException e) try s.close(); catch (IOException e1) / TODO Auto-generated catch blocke1.printStackTrace();return str;/未实现public void UDPSend() /未实现public void UDPReceive() NewChatClient:/一种布局管理器用来组织用户界面的import java.awt.BorderLayout;/颜色类 用来为用户组件添加颜色的import java.awt.Color;/一种带有位置大小的组件类import java.awt.Dimension;/一种布局管理器import java.awt.GridBagLayout;/一种图形类-长方形import java.awt.Rectangle;/事件响应的事件类import java.awt.event.ActionEvent;/事件监听类import java.awt.event.ActionListener;/一种实现了窗口接口的抽象类 import java.awt.event.WindowAdapter;/窗口的事件类import java.awt.event.WindowEvent;/数据输入流类 用来对传入数据进行输入的管道import java.io.DataInputStream;/数据输出流 用来对传出数据进行输出的管道import java.io.DataOutputStream;/IO的异常处理类import java.io.IOException;/连接的异常处理类import .ConnectException;/Socket的类 对TCP连接 进行了包装import .Socket;/Socket的异常处理类import .SocketException;/未知的主机异常类import .UnknownHostException;/日期格式类import java.text.DateFormat;/日期类import java.util.Date;/一种容器类 哈希图 用来对 键值映射的容器类import java.util.HashMap;/一种容器类import java.util.Map;/一种图形组件 窗口类import javax.swing.JFrame;/一种图形组件 标签类import javax.swing.JLabel;/一种图形组件菜单类import javax.swing.JMenu;/一种图形组件 菜单条类import javax.swing.JMenuBar;/一种图形组件 菜单项目类import javax.swing.JMenuItem;/一种图形组件 一种 组件容器类import javax.swing.JPanel;/一种图形组件 一种组件容器类 滑动条import javax.swing.JScrollPane;/一种图形组件 多行输入文本框import javax.swing.JTextArea;/一种用户界面管理类 用来对UI整体布局进行调整的管理类import javax.swing.UIManager;/一种异常处理类,处理UI皮肤异常的import javax.swing.UnsupportedLookAndFeelException;public class NewChatClient extends JFrame /构成用户界面的全局变量 有容器类和各种组件类private JPanel jContentPane = null;private JPanel jPanel_SysInfo = null;private JPanel jPanel_photo = null;private JLabel jLabel = null;private JLabel jLabel_account = null;private JPanel jPanel_state = null;private JPanel jPanel_friendTree = null;private JScrollPane jScrollPane = null;private JTextArea jTextArea_sysInfo = null;/ 两个数据流处理的类 输入和输出DataOutputStream dos = null;DataInputStream dis = null;/Socket s用来进行连接的 用户SocketSocket s = null;/用户的IDString ID = null;/用来内部线程RUN方法的启动和运行的布尔量boolean running = false;/用来在于服务器端进行同信时存储在线人员端口的变量/协议格式:当前在线#?#?#String str_Online = ;/用来处理日期信息的日期变量private Date now = null;private DateFormat df = DateFormat.getDateTimeInstance();/用来解决窗口匹配的问题,如我和你通信的窗口如果创建了就不创建新的窗口Map ChatDialogs = new

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论