Android聊天室.docx
《Android聊天室.docx》由会员分享,可在线阅读,更多相关《Android聊天室.docx(23页珍藏版)》请在冰豆网上搜索。
Android聊天室
仔仔细细手把手教你如何写一个Android聊天室,你一定能懂
今天,我们来讲Android聊天室实例开发项目,通过此项目来帮助我们了解Socket网络编程,希望对大家有所帮助。
开发之前,我们有必要了解下一些基本知识如下:
1、服务器端ServerSocket:
它常用的构造函数是ServerSocket(intport),该构造函数创建的ServerSock对象可以将这个ServerSocket绑定到一个指定的端口上,通过该程序所在计算机的IP地址以及这个端口号,客户端Socket才能连接该ServerSocket。
2、客户端Socket:
它常用的简单构造函数是Socket(Stringhost,intport),该构造函数根据两个参数连接指定的主机地址和端口号上运行的服务器程序。
注意:
在创建Socket时如果发生错误,将产生IOException,在程序中必须对之进行处理。
所以在创建Socket或ServerSocket时,必须捕获或抛出异常。
Socket常用的方法还有以下几种:
(1)、getInputStream():
返回套接字的输入流,通过得到的输入流可以获取信息。
(2)、getOutputStream():
返回此套接字的输出流,通过得到的输出流可以输出信息。
关闭Socket的方法:
每一个Socket存在时,都讲占用一定的资源,在Socket对象使用完毕时,将其关闭。
关闭Socket可以调用Socket的Close()方法。
在关闭Socket之前,应将与Socket相关的所有的输入/输出流全部关闭,以释放所有的资源。
而且要注意关闭的顺序,与Socket相关的所有的输入/输出流该首先关闭,然后再关闭Socket。
Socket通信的一般过程:
(1)、服务器端程序创建一个ServerSocket,然后调用accept()方法等待客户连接。
(2)、客户端程序创建一个Socket并请求与服务器程序建立连接。
(3)、服务器端程序接受客户端的连接请求,并创建一个新的Socket与该客户建立专线连接。
(4)、建立了连接的客户端及服务端的两个Socket在一个由服务器端程序创建的单独的线程上对话,对话的方式采用getInputStream()、getOutputStream()得到的输入与输出流进行读取与输出。
(5)、服务器端开始等待新的连接请求,重复
(2)~(5)的过程。
好了,我们有了上面的基础之后之后,我们就开始我们的Socket聊天室编程之旅吧。
首先,我们要了解下,我们这个项目的整天框架,聊天室主要包括两部分:
1、服务器端。
2、客户端;对于服务器端,我们在PC上采用纯java设计图形界面,而客户端主要是手机客户端。
下面我们就开始编写服务器端界面设计程序。
1、新建一个Java项目,命名为PCChat,在该项目中,新建一个java类,命名为Server.java,这就是PC服务器端的主界面。
2、主界面截图如下:
3、主界面代码如下:
[html]viewplaincopy
package.wyf.wpf;
importjava.awt.BorderLayout;
importjava.awt.event.ActionEvent;
importjava.awt.event.ActionListener;
importjavax.swing.JButton;
importjavax.swing.JFrame;
importjavax.swing.JPanel;
importjavax.swing.JScrollPane;
importjavax.swing.JTextArea;
publicclassSeverextendsJFrameimplementsActionListener{
//声明两个布局
BorderLayoutborderLayout1=newBorderLayout();
BorderLayoutborderLayout2=newBorderLayout();
//创建面板和按钮
JPaneljPanel1=newJPanel();
JPaneljPanel2=newJPanel();
JButtonjButton1=newJButton();
JButtonjButton2=newJButton();
JScrollPanejScrollPane1=newJScrollPane();
//创建服务器端接受消息文本框
staticJTextAreajTextArea=newJTextArea();
//声明ServerThread线程类对象
ServerThreadserverThread;
//构造函数,用于初始化面板
publicSever(){
getContentPane().setLayout(borderLayout1);
jButton1.setText("启动服务器");
jButton1.addActionListener(this);
jButton2.setText("关闭服务器");
jButton2.addActionListener(this);
this.getContentPane().add(jPanel1,BorderLayout.NORTH);
jPanel1.add(jButton1);
jPanel1.add(jButton2);
jTextArea.setText("");
jPanel2.setLayout(borderLayout2);
jPanel2.add(jScrollPane1,BorderLayout.CENTER);
jScrollPane1.getViewport().add(jTextArea);
this.getContentPane().add(jPanel2,BorderLayout.CENTER);
this.setSize(400,400);
this.setVisible(true);
}
//服务器界面中按钮事件处理
Override
publicvoidactionPerformed(ActionEvente){
//TODOAuto-generatedmethodstub
if(e.getSource()==jButton1){
serverThread=newServerThread();
serverThread.start();
}elseif(e.getSource()==jButton2){
serverThread.finalize();
this.setVisible(false);
}
}
//主函数
publicstaticvoidmain(String[]agrs){
Seversever=newSever();
sever.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
在该界面中,我们定义了两个按钮分别用于启动服务器和关闭服务器,还有一个文本框用于服务器端接受信息。
至于这个界面,用java设计,应该不陌生吧。
好了,今天就到这里,下节我们要讲,如何启动服务器。
敬请关注,。
我们编写的服务器端程序一共包括四个类,其名称及功能如下:
Server.java:
服务器端主程序负责界面,以及服务端主程序ServerThread的启动,服务端主程序ServerThread又产生BroadCaset及ClientThread线程。
BroadCast.java:
服务器向客户端广播线程,负责向客户端发送消息。
ClientThread.java:
维持服务器与单个客户端的连接线程,负责接收客户端发来的信息。
ServerThread.java:
服务器监听端口线程,负责创建服务器端ServerSocket以及监听是否有新客户端连接,并且记录客户端连接以及需要发送的信息。
上节我们设计好了启动和关闭服务器界面,这节我们主要来讲,如何启动和关闭服务器。
当Server.java文件被运行时,首先执行main方法中的代码,创建一个Server类,生成了服务器端的界面,当单击界面上得“启动服务器”按钮时,回创建一个ServerThread对象,并执行该对象中run方法的代码,所以在这里我们通过ServerThread线程来启动和关闭服务器。
下面,就来设计该类的实现。
1、首先看当单击启动服务器按钮后的界面运行效果,截图如下:
从该界面中,我们可以看到,当我们单击“启动服务器”按钮时,文本框中回出现当前的本地连接IP地址及我们设置的端口号。
2、实现效果代码如下:
[html]viewplaincopy
package.wyf.wpf;
importjava.io.IOException;
import.InetAddress;
import.ServerSocket;
import.Socket;
import.UnknownHostException;
importjava.util.Vector;
/*服务器监听端口线程*/
publicclassServerThreadextendsThread{
//指定服务器监听端口常量
privatestaticfinalintPORT=8521;
//声明ServerSocket类对象
ServerSocketserverSocket;
/*
*创建一个Vector对象,用于存储客户端连接的ClientThread对象。
*ClientThread类维持服务器与单个客户端的连接线程,负责接收客
*户端发来的信息,这里为什么使用Vector。
因为Vector有自动排序递增功能
*/
Vectorclients;
//创建一个Vector对象,用于存储客户端发送过来的信息
Vector
//声明BroadCast类,负责服务器向客户端广播信息
BroadCastbroadcast;
//声明两个变量,用于获取本地连接IP地址
Stringip;
InetAddressmyIPAddress=null;
publicServerThread(){
/*
*创建两个恶Vector数组非常重要。
clients负责存储所有与服务器建立连接
*的客户端。
message负责存储服务器接收到的未发送出去的全部客户端的信息
*/
clients=newVector();
messages=newVector
try{
serverSocket=newServerSocket(PORT);
}catch(IOExceptione){
}
try{
myIPAddress=InetAddress.getLocalHost();
}catch(UnknownHostExceptione){
System.out.println(e.toString());
}
//获取本地连接地址
ip=myIPAddress.getHostAddress();
//将该地址信息加入到jTextArea中
Sever.jTextArea.append("服务器地址:
"+ip+"端口号:
"
+String.valueOf(serverSocket.getLocalPort()+"\n"));
//启动播放消息线程,用于向客户端发送消息
broadcast=newBroadCast(this);
broadcast.start();
}
//运行线程
Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
super.run();
while(true){
try{
//在服务端获取客户端socket
Socketsocket=serverSocket.accept();
System.out.println(socket.getInetAddress().getHostAddress());
//创建客户端线程并启动
ClientThreadclientThread=newClientThread(socket,this);
clientThread.start();
//如果不为空,则将其添加到clients数组中
if(socket!
=null){
synchronized(clients){
clients.addElement(clientThread);
}
}
}catch(IOExceptionE){
System.out.println("发生异常:
"+E);
System.out.println("建立客户端联机失败!
");
System.exit
(2);
}
}
}
//关闭服务端socket
publicvoidfinalize(){
try{
serverSocket.close();
}catch(IOExceptionE){
serverSocket=null;
}
}
}
讲解:
当该类的对象被创建之时,首先创建两个数组,分别用来保存ClientThread对象和消息对象。
之后创建一个ServerSocket。
创建BroadCast对象,并且启动了该对象线程,即调用了该对象的run()方法,用以不断地向客户端发送消息。
当该类的线程被开启后,不断获取得新的客户端,并且将客户端封装在ClientThread之中,然后存于数组当中。
开启了ClientThread的线程,用以监听客户端是否有消息。
上面开发了启动与关闭服务器端线程程序,下面我们继续开发服务端程序。
其实剩下的两个线程CilentThread与BroadCast很好理解,前者就是从客户端读取信息;后者就是服务端想客户端定时发送信息。
只要把这两点看懂了,程序就不能。
好了,我就直接上代码了:
1、ClientThread.java代码如下:
[html]viewplaincopy
package.wyf.wpf;
importjava.io.DataInputStream;
importjava.io.DataOutputStream;
importjava.io.IOException;
import.Socket;
publicclassClientThreadextendsThread{
//声明客户端socket
SocketclientSocket;
//声明客户端数据输出与输入流
DataInputStreamin=null;
DataOutputStreamout=null;
//服务端线程
ServerThreadserverThread;
//构造函数,初始化相关变量
publicClientThread(Socketsocket,ServerThreadserverThread){
this.clientSocket=socket;
this.serverThread=serverThread;
try{
in=newDataInputStream(clientSocket.getInputStream());
out=newDataOutputStream(clientSocket.getOutputStream());
}catch(IOExceptione2){
System.out.println("发生异常"+e2);
System.out.println("建立I/O通道失败!
");
System.exit(3);
}
}
Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
super.run();
while(true){
try{
//读取客户端输入数据
Stringmessage=in.readUTF();
synchronized(serverThread.messages){
if(message!
=null){
//添加数据到服务端显示
serverThread.messages.addElement(message);
Sever.jTextArea.append(message+'\n');
}
}
}catch(IOExceptionE){
break;
}
}
}
}
讲解:
当该类的构造方法被调用时,获得了Socket得输入与输出流,向客户端发送数据或接受客户端数据。
Run()方法监听Socket是否有新消息,如果有新消息,则加入messages数组中。
2、编写BroadCast.java,代码如下:
[html]viewplaincopy
package.wyf.wpf;
importjava.io.IOException;
publicclassBroadCastextendsThread{
//声明服务、客户端线程
ClientThreadclientThread;
ServerThreadserverThread;
//字符串
Stringstr;
//构造函数
publicBroadCast(ServerThreadserverThread){
this.serverThread=serverThread;
}
//运行
Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
super.run();
while(true){
try{
Thread.sleep(200);
}catch(InterruptedExceptionE){
}
synchronized(serverThread.messages){
if(serverThread.messages.isEmpty()){
continue;
}
//取得消息
str=(String)this.serverThread.messages.firstElement();
}
//同步发送消息到各个客户端
synchronized(serverThread.clients){
for(inti=0;i//取得各个客户端
clientThread=(ClientThread)serverThread.clients
.elementAt(i);
try{
//客户端中写入数据
clientThread.out.writeUTF(str);
}catch(IOExceptionE){
}
}
this.serverThread.messages.removeElement(str);
}
}
}
}
讲解:
该类的run()方法每隔200ms执行一次,向所有客户端发送messages数组未发送出得消息。
好了服务端程序就到此开发完毕了。
我们的Android聊天室也告一段落了。
下面要开发的就是手机客户端。
敬请期待,!
呵呵,放了一长假回来了!
期待已久的假期结束了。
趁着这闲工夫来完结这Android聊天室的开发。
好了,让我们开始吧。
在(四)中,我们已经把服务端的程序开发完毕了!
自我感觉讲的蛮详细的!
接下来要开发的就是Android手机客户端了。
先来看下客户端运行界面吧,截图如下:
界面效果就是这样,简单吧。
下面我们就来开发这个项目的客户端。
1、创建一个Android项目,命名为ChatAndroidClient;
2、编写布局文件,这个布局应该难不倒大家,直接上代码,如下:
[html]viewplaincopy
xmlversion="1.0"encoding="utf-8"?
>
android="schemas.android./apk/res/android"
android:
layout_width="fill_parent"
android:
layout_height="fill_parent"
android:
orientation="vertical"
android:
padding="5px"
android:
layout_margin="0px"
android:
background="drawable/background_image">
android:
id="+id/nameText"
android:
layout_width="70px"
android:
layout_height="40px"
android:
paddingTop="7px"
android:
text="用户名:
"
android:
textColor="color/black"
android:
gravity="right"/>
android:
id="+id/name"
android:
layout_width="1