




已阅读5页,还剩29页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
JAVA编写QQ聊天系统指导书一、 QQ聊天系统简介1、 模拟聊天系统包含两个方面,服务器端和客户端。2、 服务器端任务:建立一个ServerSocket,与客户端建立通信通道,不断侦听是否有客户端连接或者断开连接。 服务器端是一个信息转发中心,所有客户端的信息都传到服务器端,由服务器端根据要求分发信息。3、 客户端任务:建立一个Socket,与服务器端建立通信通道,向服务器端发送信息,并接收来自服务器的信息。二、 QQ聊天系统测试1、教师机新建一个java project,命名为QQchat,将“QQ聊天系统素材”下服务器端解压,将解压后的两个包com,client复制到QQchat/src下,运行Server.java。弹出如图1-1所示图形界面,点击“开始”,将弹出如图1-2所示图形界面,服务器即打开。图1-1 图1-22、指导学生新建一个java project,命名为QQchat,在“QQ聊天系统素材”下载客户端,将客户端下载解压,将解压后的两个包com,client复制到QQchat/src下,运行Client.java,将弹出如图1-3所示图形界面,输入服务器的ip,port,以及帐户名(自已姓名)登录,将弹出如图1-4所示图形界面。点击如图1-5所示图形界面的下拉列表,在发送框中输入信息发送,就可以进行群聊或私聊。图1-3 图1-4 图1-54、 指导同学们下载服务器端,同学们轮流运行服务器程序,其它同学通过某个同学的服务器程序进行聊天。不同的服务器以IP地址区别。需要提醒学生注意的是:只有登录同一个服务器的客户端才能相互聊天,测试时服务器端只能有一个,学生们需要轮流做服务器,而客户端可以有多个,没有限制。三、 QQ聊天系统设计与实现操作步骤。F任务一 目的:通过网络编程,让同学们与老师互通字节信息。老师做服务器,学生做客户端。具体操作步骤:教师与学生都新建一个java project,命名如zhangsanQQchat(以本人姓名+QQchat为文件名),在src下新建一个other包,教师在other包下新建Server.java类并运行。指导学生在other包下新建Client.java类并运行,学生逐个与教师连接测试。通过测试,教师检查学生完成情况并记录。Server.java代码如下:package other;import java.io.*;import .*;public class Server public static void main(String args) ServerSocket server;try server=new ServerSocket(1234);Socket sk=server.accept();InputStream is=sk.getInputStream();int i;System.out.println(这是服务器端接收到的信息);while(i=is.read()!=-1)System.out.print(char)i);server.close(); catch (IOException e) e.printStackTrace();Client.java代码如下:package other;import java.io.*;import .*;public class Client public static void main(String args) Socket client;try client=new Socket(localhost,1234);OutputStream os=client.getOutputStream();os.write(z);os.write(h);os.write(a);os.write(n);os.write(s);bw.close();client.close(); catch (UnknownHostException e) e.printStackTrace(); catch (IOException e) e.printStackTrace();F任务二 目的:通过网络编程,让同学们与老师互通字节信息。学生做服务器,老师做客户端。指导学生在other包下新建Server.java类并运行。教师在other包下新建Client.java类并运行,逐个与学生连接测试,教师检查学生完成情况并记录。代码同上。网络编程总结如下:1、 在服务器端先定义一个Server.java类。在此类中的main方法中,创建一个ServerSocket 实例,指定打开一个端口,让其它机器访问。此ServerSocket 实例调用方法accept()来等待其它机器连接,若有连接返回一个Socket实例Socket实例可以调用getInputStream()方法获取客户端发来的信息。将这些信息输出,关闭各种流及连接。2、 在客户端定义一个Client.java类。在此类中main方法中,通过对指定服务器端的连接获取一个Socket实例调用这个Socket实例的getOutputStream()方法获取一个输出流,通过输出流往服务器发送信息关闭各种流及连接3、 学生先跟老师通信,然后两个同学一组,互相做客户端与服务器端,理解网络编程的基本知识。4、 由于没有引入线程知识,在做服务器端时,每连接一次后,都要重新运行Server.java。F任务三 目的:通过网络编程,让同学们与老师互通字符信息。将Server.java与 Client.java修改并运行。通过教师与学生互动测试,教师检查学生完成情况并记录。Server.java代码修改如下:package other;import java.io.*;import .*;public class Server public static void main(String args) ServerSocket server;try server=new ServerSocket(1234);Socket sk=server.accept();/返回一个字节输入流InputStream is=sk.getInputStream();/将字节流转化为字符流InputStreamReader isr=new InputStreamReader(is);/将字符流转化为缓存流BufferedReader br=new BufferedReader(isr);String s=br.readLine();System.out.println(这是服务器端接收到的信息);System.out.println(s);br.close();server.close(); catch (IOException e) e.printStackTrace();Client.java代码修改如下:package other;import java.io.*;import .*;public class Client public static void main(String args) Socket client;try client=new Socket(localhost,1234);/获取一个字节输出流OutputStream os=client.getOutputStream();/将字节输出流转化为字符输出流OutputStreamWriter osw=new OutputStreamWriter(os);/将字符输出流转化为缓存流BufferedWriter bw=new BufferedWriter(osw);bw.write(我是张三,罗老师好);bw.close();client.close(); catch (UnknownHostException e) e.printStackTrace(); catch (IOException e) e.printStackTrace();F任务总结:从上面的案例,在服务器端发现了一个缺点,每次只能与一个客户端连接,连接成功后就会退出。如何解决问题,在服务器端加上线程。F任务四 目的:客户端代码不变,在服务器端加上线程,要求服务器能与多个客户端联系。教师做服务器端,并启动服务器端,与多个同学连接,通过教师与学生互动测试,教师检查学生完成情况并记录。public class Server public static void main(String args) System.out.println(这是包含线程的服务器);ConServerThread cst=new ConServerThread();cst.startServer();new Thread(cst).start();public class ConServerThread implements Runnable/这是包含线程的服务器ServerSocket serverSocket;int count=0;public void startServer()try serverSocket=new ServerSocket(8000); catch (IOException e) e.printStackTrace();public void run() try while(true)Socket clientSocket=serverSocket.accept();InputStream ins=clientSocket.getInputStream();/*以下三行代码也可以接收字符流InputStreamReader isr=new InputStreamReader(ins);BufferedReader bfr=new BufferedReader(isr); String str= bfr.readLine();*/推荐使用下面方法接收字符DataInputStream dis=new DataInputStream(ins);String str=dis.readUTF();System.out.println(这是从客户端传过来的信息:+str);count+;System.out.println(这是第+count+个连接客户); catch (IOException e) e.printStackTrace();F任务五 目的:客户端代码不变,在服务器端加上线程。学生做服务器端,并启动服务器端,教师逐个与每个同学连接,通过教师与学生互动测试,教师检查学生完成情况并记录。F任务总结:流的知识回顾,BufferedWriter 中的方法BufferedWriter()有这个一样缺点,当我们输入文字太少的时候,如果缓存没装满的时候,它不会发送出去,除非调用close方法。在实际操作中,同学们信息发送不成功的同学可能就是这个原因。这个方法不便于连续发送,所以采用DataInputStream(InputSream)来处理InputStream,调用他的readUTF()方法来读,输出流也一样,调用writerUTF()方法来写,它就不要求关闭,可以连续写与读内容。另外从任务四中,在服务器端又发现了一个缺点,虽然可以与多个客户端连接,但每次只能接收一句话。如何解决问题,在服务器端再加线程。F任务六 目的:客户端代码不变,在服务器端加上线程,要求完成服务器不仅要与多个客户端连接,而且可以接受一个客户的多条语句。教师做服务器端,并启动服务器端,每个同学与服务器连接,通过教师与学生互动测试,教师检查学生完成情况并记录。public class Server public void startServer()try serverSocket=new ServerSocket(8000);new Thread(new StartServerThread().start(); catch (IOException e) e.printStackTrace();/下面这个线程类中类,能够完成服务器可以与多个客户端连接,不用线程的话与一个客户端连接后就会结束程序。class StartServerThread implements Runnablepublic void run() while(true)try clientSocket=serverSocket.accept();new Thread(new ServerReadThread(clientSocket).start(); catch (IOException e) e.printStackTrace();/下面这个线程类中类,能够完成服务器可以可以接受一个客户的多条信息。不用线程的话,服务器只能接受一条语句。class ServerReadThread implements RunnableSocket clientSocket;public ServerReadThread(Socket clientSocket) this.clientSocket=clientSocket;FFpublic void run() try InputStream ins=clientSocket.getInputStream(); DataInputStream dataIn = new DataInputStream(ins);while(true)String str= dataIn.readUTF();System.out.println(str); catch (IOException e) e.printStackTrace(); public static void main(String args) new Server();F任务七 目的:客户端代码不变,在服务器端加上线程,要求完成服务器不仅要与多个客户端连接,而且可以接受一个客户的多条语句。学生做服务器端,并启动服务器端,教师作为客户端逐个与每个同学连接,通过教师与学生互动测试,教师检查学生完成情况并记录。F任务八 目的:在src/client,src/server下创建图形界面文件。其中图1-6为文件GuiServer.java运行结果,该文件在src/server下, 图1-7为文件GuiClientMain.java运行结果,图1-8为文件CuiClient.java运行结果,文件所在目录结构如图1-9所示。图1-6 图1-7 图1-8 图1-9 注意:学生完成了以上图形界面类的创建,教师作为一次作业检查,学生保存,由于图形界面不是重点,为便于逻辑的实现,统一教学进度,下面的图形界面统一采用教师提供的文件,学生将老师提供的图形界面复制到自已相应的包下(图形界面文件素材在“QQ聊天系统素材”下的“图形界面”下),如上图1-9所示。学生可以在业余时间,采用自已设计的图形界面完成本项目。附三个文件的代码GuiServer.java:public class GuiServer extends Frame /写三个组件privateTextArea text = new TextArea(, 10,40);privateButton startButton = new Button(开始);private Button closeButton = new Button(结束);/写了三个容器privatePanel p1 = new Panel();private Panel p2 = new Panel();private Panel p3 = new Panel();public GuiServer() super(某某服务器);p1.add(startButton);p1.add(closeButton);p2.add(text);this.add(p2,BorderLayout.NORTH);this.add(p1,BorderLayout.CENTER);this.pack();this.setVisible(true);public class GuiClient extends Frameprivate Button sendButton;private Button closeButton;private TextArea receiveMsg ;private TextArea sendMsg ;private GuiClient frm;private Choice clientList;public GuiClient(String str)super(str);frm = this;clientList = new Choice();this.clientList.add(ALL );receiveMsg = new TextArea(5 , 20);sendMsg = new TextArea(5 , 20);this.sendMsg.setText();this.receiveMsg.setText(); this.sendButton = new Button(发送);this.closeButton = new Button(退出);Panel p = new Panel();Panel p1 = new Panel();Panel p2 = new Panel();Panel p3 = new Panel();Panel p4 = new Panel();frm.add(p);p.setLayout(new BorderLayout();p.add(p1,North);p.add(p2,Center);p2.add(p4);p.add(p3,South);p1.setLayout(new FlowLayout();p1.add(clientList);p4.setLayout(new GridLayout(2,1);p4.add(receiveMsg);p4.add(sendMsg);p3.setLayout(new FlowLayout();p3.add(this.sendButton);p3.add(this.closeButton);frm.add(p);/showFrame()方法的作用是将窗口显示在指定的地方public void showFrame()Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();Dimension frameSize = frm.getSize();frm.setLocation(screenSize.width-frameSize.width-200)/2,(screenSize.height-frameSize.height-100)/2);frm.pack();frm.setVisible(true);public void listenSendButton(final Client b) this.sendButton.addActionListener( new ActionListener() public void actionPerformed(ActionEvent e) b.send(); ); public void listenCloseButton(final Client b) this.closeButton.addActionListener( new ActionListener() public void actionPerformed(ActionEvent e) b.quit(); ); public class GuiClientMain extends Frameprivate TextField address;private TextField port;private TextField userName;private Button loginButton ;privateButton qutiButton ;private Frame clientmainframe;public GuiClientMain(String str)super(str);clientmainframe = this;Label label1 = new Label(服务器 IP:);Label label2 = new Label(服务器port:);Label label3 = new Label(QQ 用户名:);this.loginButton = new Button(登录);this.qutiButton = new Button(取消);this.address = new TextField(null,20);this.port = new TextField(null,20);this.userName = new TextField(null , 20);Panel p1 = new Panel();Panel p2 = new Panel();Panel p3 = new Panel();Panel p4 = new Panel();clientmainframe.setLayout(new GridLayout(4,1);p1.setLayout(new FlowLayout();p2.setLayout(new FlowLayout();p3.setLayout(new FlowLayout();p4.setLayout(new FlowLayout();p1.add(label1);p1.add(this.address);p2.add(label2);p2.add(this.port);p3.add(label3);p3.add(this.userName);p4.add(this.loginButton);p4.add(this.qutiButton);clientmainframe.add(p1);clientmainframe.add(p2);clientmainframe.add(p3);clientmainframe.add(p4);clientmainframe.addWindowListener(new WindowAdapter()public void windowClosing(WindowEvent e)System.exit(0););/showFrame()方法的作用是将窗口显示在指定的地方public void showFrame()Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();Dimension frameSize = clientmainframe.getSize();clientmainframe.setLocation(screenSize.width-frameSize.width-200)/2,(screenSize.height-frameSize.height-100)/2);clientmainframe.pack();clientmainframe.setVisible(true);public void listenLoginButton(final Client b)this.loginButton.addActionListener(new ActionListener()public void actionPerformed(ActionEvent e) b.login(); );public void listenQuitButton(final Client b)this.qutiButton.addActionListener(new ActionListener()public void actionPerformed(ActionEvent e) System.exit(0); );F任务九 目的:利用图形界面图一中“开始”按钮启动服务器,“退出”按钮关闭服务器。具体操作如下:1、 修改GuiServer.java中的开始按钮监听的方法。代码如下:public void startButListenter(final Server a)startButton.addActionListener(new ActionListener()public void actionPerformed(ActionEvent e) text.setText(服务器开始工作了。);a.startServer(););这段代码表达的是当我们点击了startButton,就跳转到了Server.java中方法startServer()。2、 在Server.java中startServer()方法完成开启服务器的工作。代码如下:public void startServer()try serverSocket=new ServerSocket(8000);new Thread(new StartServerThread().start(); catch (IOException e) e.printStackTrace();3、 线程类StartServerThread的代码如下:class StartServerThread implements Runnableint count=0;public void run() while(true)try Socket clientSocket=serverSocket.accept();InputStream ins=clientSocket.getInputStream();DataInputStream dataIn = new DataInputStream(ins);String str= dataIn.readUTF();System.out.println(这是从客户端传过来的信息:+str);count+;System.out.println(这是第+count+个连接客户); catch (IOException e) e.printStackTrace();4、 如何实现点击退出按钮,就关闭服务器?修改GuiServer.java中的退出按钮监听的方法。public void endButtonListenter(final Server a)closeButton.addActionListener(new ActionListener()public void actionPerformed(ActionEvent e) a.endServer(););这段代码表达的是当我们点击了closeButton ,就跳转到了Server.java中方法endServer ()。Server.java中方法endServer ()代码如下:public void endServer()System.exit(0);F任务十:客户端利用图形界面登录到指定的服务器,并且发送消息给服务器。具体操作如下:1、 运行Client.java,先调用构造器,构造器中调用按钮监听,点击登录按钮,程序跳转到Client.java中的login()方法,在login()中实现将图形界面输入的内容打印输出。2、 在GuiClientMain.java中加入三个方法,用于获取三个文本框的值。代码如下:public String getAddress() return address.getText();public int getPort() String port1=port.getText();int port2=Integer.parseInt(port1);return port2;public String getUserName() return userName.getText();3、Client.java中的login()方法如下:public void login()try/首先要获取登录框中的内容,即用户输入的数据String severIP=guiMain.getAddress();int serverPort=guiMain.getPort();userName=guiMain.getUserName();System.out.println(severIP=+severIP);System.out.println(serverPort=+serverPort);System.out.println(userName=+userName);client = new Socket(severIP,serverPort);System.out.println(与服务器连接成功。);ous=client.getOutputStream();DataOutputStream dataOut = new DataOutputStream(ous);dataOut.writeUTF(IP为+severIP+ ; Port为+serverPort+的人在联系你。);dataOut.writeUTF(用户名是:+userName);/这个IP前面带一个斜杆/String clientIp=client.getLocalAddress().toString();/下面代码将斜杆去掉。String clientIp=client.getLocalAddress().toString().substring(1);int clientPort=client.getLocalPort();System.out.println(我的IP是:+clientIp);System.out.println(我的port是:+clientPort);/登录界面退出guiMain.dispose();/聊天界面显示/调用send按钮监听方法,那么点击send按钮就会跳到send()方法gui.listenSendButton(this);/点击close按钮就会跳到quit()方法gui.listenCloseButton(this);gui.setTitle(userName);gui.showFrame();gui.addWindowListener(new WindowAdapter()public void windowClosing(WindowEvent e) quit(); );/new Thread(new ReadThread().start();catch(Exception e)System.out.println(e);System.out.println(连接有误,请检查服务器是否打开,或者服务器IP地址与端口号是否有误!);public void send()System.out.println(send);try String msg=gui.getSendMsg();System.out.println(msg=+msg);ous=client.getOutputStream();ous=client.getOutputStream();DataOutputStream dataOut = new DataOutputStream(ous);dataOut.writeUTF(userName+说:+msg);gui.setSendMsgClear(); catch (IOException e) / TODO Auto-generated catch blocke.printStackTrace();思考:在QQ聊天系统中,服务器是如何知道是哪个客户发来的信息呢?Socket中有两个方法可以将连接服务器的客户端的Ip和port获取,这也是服务器知道是哪个客户发过来信息的原因,也是后面服务器将消息发送给某个客户端的基础。Socket实例两个方法getLocalAddress(),与getLocalPort(),可以获取客户端的Ip和port获取。clientSocket.getLocalAddress();clientSocket.getLocalPort();F任务十一:客户端将自身的Ip和port获取,当与服务器成功连接后,将自身的Ip和port以一定的消息格式传给服务器。具体代码如下:/获取客户端的IP与portString clientIp=clientSocket1.getLocalAddress().toString().substring(1);int clientPort=clientSocket1.getLocalPort();System.out.println(本客户端IP为:+clientIp);System.out.println(本客户端Port为:+clientPort);/注意这个clientIp前面有一个斜杆,还要处理下。/按消息规则发送消息String str=NEW/+clientIp+/+clientPort+/+userName+/;dos.writeUTF(str);F任务十二:实现用聊天对话框的发送框向服务器发送信息。如下图所示。分析聊天原理:与服务器连接成功的客户,服务器端都能获取它的IP与Port,每一个客户的IP与Port都不会相同,所以我们用Ip与Port可以区分每个客户,这也是聊天系统成功的基本原理。所以在登录的时候,就将这些信息发送给了服务器,让服务器知道有哪些客户上线了。服务器在转发消息时,通过选择客户的IP与Port来发送给指定的客户,作为客户端,一要告诉服务器你本身的IP与Port,二要告诉服务器你的信息发给谁,也是通过IP与port来确定,所以说在login()方法中既要发送自已的IP与Port给服务器,在send()方法中,我们还要将接收方的IP与Port发送服务器,服务器将如何辨认哪个是你自已的IP与Port,哪个是你将要发送的客户的IP与Port,那么你就要做个标记。如你在登录时发的,说明是你自已的IP与Port,前面加个前缀“NEW”,你在send()方法中发送的我们就加一个前缀“MSG”,服务器接收到以后,通过前缀就可以分类处理。总结聊天系统中消息的发送,都要发送IP,Port, 用户名,消息,而且遵循整发散取的原则,意思是整合发过去,到了对方,都要打散它,为了便于整合与打散,所以我们定义一下消息格式,便于后面写方法专门来处理整合、打散字符串。我们最多发送五个内容给服务器,所以设计了下面这个格式:五个内容之间用斜线分开,每次可以发送小于或等于五个内容的消息。如果小于五个内容,在具体地方发送空格就行。消息格式规定为:head/+ip+/+port+/+usename+/+sendmsgF任务十三:客户端登录时将自已相关的信息发送给服务器,服务器将这些信息接到后,将这些信息拆开并输出。当前缀不同时按不同的方式处理。处理方式如下 :对于登录时,head=”NEW”, ip=本客户的IP, port=本客户的Port,username=本客户的用户名,sendmsg=”;整发:(客户端)dos.writeUTF(NEW/+clientIp+/+clientPort+/+userName+/);散取:(服务器)String str=dis.readUTF();System.out.println(来自客
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 儿科学测试题及答案-免疫性疾病
- 2025年美容美发师招聘面试题及答案参考
- 2025见证取样员考试题库及答案
- 2025年注册验船师资格考试(C级船舶检验法律法规)复习题及答案二
- 2025年公路水运工程试验检测师《桥梁隧道工程》考试题库及答案
- 2025年汽车销售市场招聘笔试题目及答案解析
- 桥梁修补专业知识培训内容课件
- 桑葚养护知识培训课件
- 2025年注册验船师资格考试(C级船舶检验法律法规)冲刺模拟试题及答案一
- 2025年珲春市老年人健康管理试题及答案(培训前)
- 2019译林版高中英语全七册单词总表
- 《湖北省安全生产条例》考试复习题库80题(含答案)
- 《义务教育语文课程标准》(2022年版)原文
- 《建筑防排烟工程》 课件 1火灾烟气的产生及危害
- 墙体 砌块墙的构造(建筑构造)
- 离网光伏发电系统方案
- 研学旅行教师指导手册
- 锂资源行业的合规管理与风险控制
- 电商运营专员劳动合同
- project2016使用教程课件
- 青岛殡葬服务流程
评论
0/150
提交评论