河北大学工商学院实验报告学部:理工学部课程名称:软件工程工具实验项目:聊天系统专业班级:姓名:学号:实验地点:B3-403指导教师:杨柳成绩:1 实验目的(1)解决工作和生活中的信息交流不便的弊端。
(2)掌握基于Socket的聊天程序的设计方法。
(3)使用C/S构架,对网络编程有一定的了解。
2 实验要求(1)使用Socket异步套接字进行通信,实现点对点发送消息的功能。
3 实验内容3.1 系统概述为了解决工作和生活中信息交流不变的弊端,设计和实现一个基于C/S结构的聊天系统。
本系统使用Socket异步套接字进行通信,实现点对点发送消息的功能。
该系统包括服务器端和客户端,服务器端的主要功能是使用Socket监听本机的端口,如果有连接请求则创建Socket连接,而客户端在使用时需要对服务器的端口发出请求,如果服务器存在,则建立连接,实现服务器端和客服端之间的通信。
3.2 系统分析与设计(1)使用前首先建立Socket连接。
(2)服务器端与客户端之间的信息发送是该系统最基本的功能。
(3)在C/S模式中,服务器与客户端是相互依赖的。
(4)服务器端与客户端的聊天信息在界面的显示应按照用户的要求进行格式处理,这样更易于用户查看。
3.3 系统实现与测试系统用例图:系统时序图:发送消息结束消息Server.java①单击启动按钮事件若服务器已启动则提示错误。
若正常,启动服务器。
public void serverStart(int max, int port) throws .BindException ;当端口号被占用则提示错误信息,若没有错误,则进行以下代码,启动服务器。
clients=new ArrayList<ClientThread>();serverSocket=new ServerSocket(port);serverThread=new ServerThread(serverSocket,max); serverThread.start();isStart=true;②单击停止按钮停止服务器,若服务器未曾启动或停止失败则报错关闭服务器的方法public void closeServer()停止服务器线程,并给所有在线用户发送关闭命令,释放资源,停止此条为客户端服务的线程,关闭服务器端连接清空用户列表③群发服务器消息public void sendServerMessage(String message){for(int i=clients.size() - 1;i>=0;i--){clients.get(i).getWriter().println("服务器:"+message+"(多人发送)"); clients.get(i).getWriter().flush();}}④服务器线程class ServerThread extends Thread{}内含构造方法和run方法public void run(){while(true){//try{Socket socket=serverSocket.accept();服务器不停的等待客户端的链接。
如果已达人数上限,提示“服务器在线人数已达上限,请稍后尝试连接”,并释放资源若符合要求,则开启对此客户端服务的线程ClientThread client=new ClientThread(socket);client.start();clients.add(client);listModel.addElement(client.getUser().getName());contentArea.append(client.getUser().getName()+client.getUser().getIp() +"上线!\r\n");为一个客户端服务的线程class ClientThread extends Thread {客户端线程的构造方法接收客户端的基本用户信息,反馈连接成功信息,反馈当前在线用户信息向所有在线用户发送该用户上线命令run方法不断接收客户端的消息,进行处理。
下线命令断开连接释放资源,向所有在线用户发送该用户的下线命令更新在线列表,删除此条客户端服务线程⑤执行消息发送函数send()public void send() ;服务器还未启动或没有用户在线时,不能发送消息,提示错误。
消息不为空时将消息群发。
⑥转发消息dispatcherMessage()public void dispatcherMessage(String message){StringTokenizer stringTokenizer=new StringTokenizer(message,"@"); String source=stringTokenizer.nextToken();String owner=stringTokenizer.nextToken();String content=stringTokenizer.nextToken();message=source+"说:"+content;contentArea.append(message+"\r\n");if(owner.equals("ALL")){//群发for(int i=clients.size() - 1;i>=0;i--){clients.get(i).getWriter().println(message+"(多人发送)");clients.get(i).getWriter().flush();}}}}}Client.java1.Send()函数如果没有连接服务器时,不能发送消息,弹出提示;若服务器已连接,则判断消息是否为空,消息为空则提示错误信息,不为空时调用sendMessage()函数将消息发出,textField清空。
public void send() { if (!isConnected) {JOptionPane.showMessageDialog(frame, "还没有连接服务器,无法发送消息!", "错误",JOptionPane.ERROR_MESSAGE);return;}String message = textField.getText().trim();if (message == null || message.equals("")) {JOptionPane.showMessageDialog(frame, "消息不能为空!", "错误",JOptionPane.ERROR_MESSAGE);return;}sendMessage(frame.getTitle() + "@" + "ALL" + "@" + message);textField.setText(null);}2.单击连接按钮时事件单击连接按钮时,如果处于连接上状态,则提示不能重复链接。
if (isConnected) {JOptionPane.showMessageDialog(frame, "已处于连接上状态,不要重复连接!","错误", JOptionPane.ERROR_MESSAGE);return;}判断端口、IP地址、姓名是否为空,如果为空,抛出异常,提示错误信息,否则提示连接成功。
3.单击断开按钮时事件单击断开按钮时,如果处于断开上状态,则提示不能重复断开抛出异常,通过设置flag调用closeConnection()调用判断服务器是否成功断开。
btn_stop.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {if (!isConnected) {JOptionPane.showMessageDialog(frame, "已处于断开状态,不要重复断开!","错误", JOptionPane.ERROR_MESSAGE);return;}try {boolean flag = closeConnection();// 断开连接if (flag == false) {throw new Exception("断开连接发生异常!");}JOptionPane.showMessageDialog(frame, "成功断开!");} catch (Exception exc) {JOptionPane.showMessageDialog(frame,exc.getMessage(),"错误", JOptionPane.ERROR_MESSAGE);}}});4.单击发送按钮事件直接调用send()函数,完成发送。
btn_send.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {send();}});5.连接服务器函数connectServer()socket描述IP地址和端口,根据端口号和服务器ip建立连接,是一个通信链的句柄。
getInputStream方法获得网络连接输入,同时返回一个InputStream对象实例,赋值给writer, getOutputStream 方法连接的另一端将得到输入,同时返回一个OutputStream对象实例,赋给reader。
socket = new Socket(hostIp, port);//writer = new PrintWriter(socket.getOutputStream());reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));接着通过sendMessage()函数发送客户端用户基本信息(用户名和ip 地址),开启接收消息的线程,调用start()函数,如果连接成功,返回TRUE,messageThread = new MessageThread(reader, textArea);messageThread.start();isConnected = true;// 已经连接上了return true;否则补货,返回FALSE。