JAVA编写QQ聊天系统指导书.docx
《JAVA编写QQ聊天系统指导书.docx》由会员分享,可在线阅读,更多相关《JAVA编写QQ聊天系统指导书.docx(49页珍藏版)》请在冰点文库上搜索。
JAVA编写QQ聊天系统指导书
JAVA编写QQ聊天系统指导书
一、QQ聊天系统简介
1、模拟聊天系统包含两个方面,服务器端和客户端。
2、服务器端任务:
建立一个ServerSocket,与客户端建立通信通道,不断侦听是否有客户端连接或者断开连接。
服务器端是一个信息转发中心,所有客户端的信息都传到服务器端,由服务器端根据要求分发信息。
3、客户端任务:
建立一个Socket,与服务器端建立通信通道,向服务器端发送信息,并接收来自服务器的信息。
二、QQ聊天系统测试
1、教师机新建一个javaproject,命名为QQchat,将“QQ聊天系统素材”下服务器端
解压,将解压后的两个包com,client复制到QQchat/src下,运行Server.java。
弹出如图1-1所示图形界面,点击“开始”,将弹出如图1-2所示图形界面,服务器即打开。
图1-1图1-2
2、指导学生新建一个javaproject,命名为QQchat,在“QQ聊天系统素材”下载客户端
,将客户端下载解压,将解压后的两个包com,client复制到QQchat/src下,运行Client.java,将弹出如图1-3所示图形界面,输入服务器的ip,port,以及帐户名(自已姓名)登录,将弹出如图1-4所示图形界面。
点击如图1-5所示图形界面的下拉列表,在发送框中输入信息发送,就可以进行群聊或私聊。
图1-3图1-4图1-5
4、指导同学们下载服务器端,同学们轮流运行服务器程序,其它同学通过某个同学的服务器程序进行聊天。
不同的服务器以IP地址区别。
需要提醒学生注意的是:
只有登录同一个服务器的客户端才能相互聊天,测试时服务器端只能有一个,学生们需要轮流做服务器,而客户端可以有多个,没有限制。
三、QQ聊天系统设计与实现操作步骤。
任务一目的:
通过网络编程,让同学们与老师互通字节信息。
老师做服务器,学生做客户端。
具体操作步骤:
教师与学生都新建一个javaproject,命名如zhangsanQQchat(以本人姓名+QQchat为文件名),在src下新建一个other包,教师在other包下新建Server.java类并运行。
指导学生在other包下新建Client.java类并运行,学生逐个与教师连接测试。
通过测试,教师检查学生完成情况并记录。
Server.java代码如下:
packageother;
importjava.io.*;
import.*;
publicclassServer{
publicstaticvoidmain(String[]args){
ServerSocketserver;
try{
server=newServerSocket(1234);
Socketsk=server.accept();
InputStreamis=sk.getInputStream();
inti;
System.out.println("这是服务器端接收到的信息");
while((i=is.read())!
=-1){
System.out.print((char)i);
}
server.close();
}catch(IOExceptione){
e.printStackTrace();
}}
}
Client.java代码如下:
packageother;
importjava.io.*;
import.*;
publicclassClient{
publicstaticvoidmain(String[]args){
Socketclient;
try{
client=newSocket("localhost",1234);
OutputStreamos=client.getOutputStream();
os.write('z');
os.write('h');
os.write('a');
os.write('n');
os.write('s');
bw.close();
client.close();
}catch(UnknownHostExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
任务二目的:
通过网络编程,让同学们与老师互通字节信息。
学生做服务器,老师做客户端。
指导学生在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。
任务三目的:
通过网络编程,让同学们与老师互通字符信息。
将Server.java与Client.java修改并运行。
通过教师与学生互动测试,教师检查学生完成情况并记录。
Server.java代码修改如下:
packageother;
importjava.io.*;
import.*;
publicclassServer{
publicstaticvoidmain(String[]args){
ServerSocketserver;
try{
server=newServerSocket(1234);
Socketsk=server.accept();
//返回一个字节输入流
InputStreamis=sk.getInputStream();
//将字节流转化为字符流
InputStreamReaderisr=newInputStreamReader(is);
//将字符流转化为缓存流
BufferedReaderbr=newBufferedReader(isr);
Strings=br.readLine();
System.out.println("这是服务器端接收到的信息");
System.out.println(s);
br.close();
server.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
Client.java代码修改如下:
packageother;
importjava.io.*;
import.*;
publicclassClient{
publicstaticvoidmain(String[]args){
Socketclient;
try{
client=newSocket("localhost",1234);
//获取一个字节输出流
OutputStreamos=client.getOutputStream();
//将字节输出流转化为字符输出流
OutputStreamWriterosw=newOutputStreamWriter(os);
//将字符输出流转化为缓存流
BufferedWriterbw=newBufferedWriter(osw);
bw.write("我是张三,罗老师好");
bw.close();
client.close();
}catch(UnknownHostExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
任务总结:
从上面的案例,在服务器端发现了一个缺点,每次只能与一个客户端连接,连接成功后就会退出。
如何解决问题,在服务器端加上线程。
任务四目的:
客户端代码不变,在服务器端加上线程,要求服务器能与多个客户端联系。
教师做服务器端,并启动服务器端,与多个同学连接,通过教师与学生互动测试,教师检查学生完成情况并记录。
publicclassServer{
publicstaticvoidmain(String[]args){
System.out.println("这是包含线程的服务器");
ConServerThreadcst=newConServerThread();
cst.startServer();
newThread(cst).start();
}
}
publicclassConServerThreadimplementsRunnable{
//这是包含线程的服务器
ServerSocketserverSocket;
intcount=0;
publicvoidstartServer(){
try{
serverSocket=newServerSocket(8000);
}catch(IOExceptione){
e.printStackTrace();
}
}
publicvoidrun(){
try{
while(true){
SocketclientSocket=serverSocket.accept();
InputStreamins=clientSocket.getInputStream();
/*以下三行代码也可以接收字符流
InputStreamReaderisr=newInputStreamReader(ins);
BufferedReaderbfr=newBufferedReader(isr);
Stringstr=bfr.readLine();
*/
//推荐使用下面方法接收字符
DataInputStreamdis=newDataInputStream(ins);
Stringstr=dis.readUTF();
System.out.println("这是从客户端传过来的信息:
"+str);
count++;
System.out.println("这是第"+count+"个连接客户");
}
}catch(IOExceptione){
e.printStackTrace();
}
}
}
任务五目的:
客户端代码不变,在服务器端加上线程。
学生做服务器端,并启动服务器端,教师逐个与每个同学连接,通过教师与学生互动测试,教师检查学生完成情况并记录。
任务总结:
流的知识回顾,BufferedWriter中的方法BufferedWriter()有这个一样缺点,当我们输入文字太少的时候,如果缓存没装满的时候,它不会发送出去,除非调用close方法。
在实际操作中,同学们信息发送不成功的同学可能就是这个原因。
这个方法不便于连续发送,所以采用DataInputStream(InputSream)来处理InputStream,调用他的readUTF()方法来读,输出流也一样,调用writerUTF()方法来写,它就不要求关闭,可以连续写与读内容。
另外从任务四中,在服务器端又发现了一个缺点,虽然可以与多个客户端连接,但每次只能接收一句话。
如何解决问题,在服务器端再加线程。
任务六目的:
客户端代码不变,在服务器端加上线程,要求完成服务器不仅要与多个客户端连接,而且可以接受一个客户的多条语句。
教师做服务器端,并启动服务器端,每个同学与服务器连接,通过教师与学生互动测试,教师检查学生完成情况并记录。
publicclassServer{
publicvoidstartServer(){
try{
serverSocket=newServerSocket(8000);
newThread(newStartServerThread()).start();
}catch(IOExceptione){
e.printStackTrace();
}
}
//下面这个线程类中类,能够完成服务器可以与多个客户端连接,不用线程的话与一个客户端连接后就会结束程序。
classStartServerThreadimplementsRunnable{
publicvoidrun(){
while(true){
try{
clientSocket=serverSocket.accept();
newThread(newServerReadThread(clientSocket)).start();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
}
//下面这个线程类中类,能够完成服务器可以可以接受一个客户的多条信息。
不用线程的话,服务器只能接受一条语句。
classServerReadThreadimplementsRunnable{
SocketclientSocket;
publicServerReadThread(SocketclientSocket){
this.clientSocket=clientSocket;
}
publicvoidrun(){
try{
InputStreamins=clientSocket.getInputStream();
DataInputStreamdataIn=newDataInputStream(ins);
while(true){
Stringstr=dataIn.readUTF();
System.out.println(str);
}
}catch(IOExceptione){
e.printStackTrace();
}
}
}
publicstaticvoidmain(String[]args){
newServer();
}
}
任务七目的:
客户端代码不变,在服务器端加上线程,要求完成服务器不仅要与多个客户端连接,而且可以接受一个客户的多条语句。
学生做服务器端,并启动服务器端,教师作为客户端逐个与每个同学连接,通过教师与学生互动测试,教师检查学生完成情况并记录。
任务八目的:
在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:
publicclassGuiServerextendsFrame{
//写三个组件
privateTextAreatext=newTextArea("",10,40);
privateButtonstartButton=newButton("开始");
privateButtoncloseButton=newButton("结束");
//写了三个容器
privatePanelp1=newPanel();
privatePanelp2=newPanel();
privatePanelp3=newPanel();
publicGuiServer(){
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);
}
}
publicclassGuiClientextendsFrame{
privateButtonsendButton;
privateButtoncloseButton;
privateTextAreareceiveMsg;
privateTextAreasendMsg;
privateGuiClientfrm;
privateChoiceclientList;
publicGuiClient(Stringstr){
super(str);
frm=this;
clientList=newChoice();
this.clientList.add("ALL");
receiveMsg=newTextArea(5,20);
sendMsg=newTextArea(5,20);
this.sendMsg.setText("");
this.receiveMsg.setText("");
this.sendButton=newButton("发送");
this.closeButton=newButton("退出");
Panelp=newPanel();
Panelp1=newPanel();
Panelp2=newPanel();
Panelp3=newPanel();
Panelp4=newPanel();
frm.add(p);
p.setLayout(newBorderLayout());
p.add(p1,"North");
p.add(p2,"Center");
p2.add(p4);
p.add(p3,"South");
p1.setLayout(newFlowLayout());
p1.add(clientList);
p4.setLayout(newGridLayout(2,1));
p4.add(receiveMsg);
p4.add(sendMsg);
p3.setLayout(newFlowLayout());
p3.add(this.sendButton);
p3.add(this.closeButton);
frm.add(p);
}
//showFrame()方法的作用是将窗口显示在指定的地方
publicvoidshowFrame(){
DimensionscreenSize=Toolkit.getDefaultToolkit().getScreenSize();
DimensionframeSize=frm.getSize();
frm.setLocation((screenSize.width-frameSize.width-200)/2,(screenSize.height-frameSize.height-100)/2);
frm.pack();
frm.setVisible(true);
}
publicvoidlistenSendButton(finalClientb){
this.sendButton.addActionListener(newActionListener(){
publicvoidactionPerformed(ActionEvente){
b.send();
}
});
}
publicvoidlistenCloseButton(finalClientb){
this.closeButton.addActionListener(newActionListener(){
publicvoidactionPerformed(ActionEvente){
b.quit();
}
});
}
publicclassGuiClientMainextendsFrame{
privateTextFieldaddress;
privateTextFieldport;
privateTextFielduserName;
privateButtonloginButton;
privateButtonqutiButton;
privateFrameclientmainfr