android聊天室设计.docx
- 文档编号:11568689
- 上传时间:2023-03-19
- 格式:DOCX
- 页数:21
- 大小:278.36KB
android聊天室设计.docx
《android聊天室设计.docx》由会员分享,可在线阅读,更多相关《android聊天室设计.docx(21页珍藏版)》请在冰豆网上搜索。
android聊天室设计
嵌入式课程设计(论文)
Androidl聊天室设计
学生:
学号:
指导教师:
李季老师
专业:
计算机科学与技术
重庆大学计算机学院
二O一一年十二月
摘要
此系统设计了一个基于Android系统与PC之间的通信,采用Socket流式套接字进行网络通信。
其中Android系统的模拟器作为客户端,客户端采用获取手机号码作为该客户端的唯一标识,PC作为服务器端。
其中客户端的设计过程中主要用ChatClientActivity文件实现客户端的各个Widget的功能以及利用Socket向服务器端发送和接受服务器端的消息。
服务器端主要用ServerThread服务器线程初始化ServerSocket并将对客户端监听到得Socket封装到ClientThread线程中并将该线程存放到Vector数组用于服务器与指定客户端交互,以及启动BroadCast线程和ClientThread线程,以及将,其中ClientThread线程主要用于将监听到客户端发送的消息存放到消息队列并将其保存在SQL2000数据库中以及根据分类显示在控制台上,BroadCast线程主要获取消息队列中的消息并根据消息的性质确定是否将此消息广播到所有在线客户端或是发送到某些指定的客户端。
StartServer主要用于启动ServerThread线程,即启动整个服务器。
DoDataBase主要用于连接数据库和实现对数据库的添加操作。
最后此系统实现了群聊与私聊的功能,并能够将聊天记录分类保存到数据库中。
关键词:
Android,Socket通信,线程同步,TCP/IP协议
目录
中文摘要Ⅰ
1TCP/IP及Socket简介1
1.1TCP/IP协议简介1
1.2Socket套接字简介1
2系统总体架构2
3系统功能实现3
3.1数据交互格式3
3.2服务器功能实现4
3.2.1StartServer类4
3.2.2ServerThread类5
3.2.3ClientThread类6
3.2.4BroadCast类8
3.2.1DoDataBase类10
3.3客户端功能实现11
3.4系统功能展示15
3.4.1客户端功能展示15
3.4.2服务器端及数据库展示16
4系统存在的问题及改进方法17
4.1系统存在的问题17
4.2系统改进方法17
4自我评价18
参考文献19
1TCP/IP及Socket简介
1.1TCP/IP协议简介
TCP/IP是TransmControlProtocol/InternetProtocol的简写,又称网络通信协议,是Internet最基本的协议。
TCP/IP协议是“可靠的”、“面相连接”的网络传输协议。
TCP/IP协议遵循的是一个抽象的分层模型,这个模型中所有的TCP/IP系列网络协议都被归纳到四个抽象的“层”中。
每一抽象层建立在低一层提供的服务上,并为高一层服务。
TCP/IP参考模型从上到下分别包括网络接口层、网络互连层、传输层和应用层四层。
1.2Socket套接字简介
在网络上的两个程序通过一个双向的通信链路实现数据交换,这个双向链路的一段就被称为一个Socket,Socket通常用来实现客户端和服务器端的链接。
Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket有一个IP地址和一个端口号确定。
在Java环境中实现基于TCP/IP协议的网络编程都需要采用Socket机制。
并且与基于URL的网络编程Socket编程提供更高的传输效率。
Socket通常采用C/S结构,使用Socket进行C/S程序设计的一般链接过程如下图:
图1.1Socket编程连接一般过程
2系统总体架构
整个系统由客户端和服务器端组成,其中客户端位于Android模拟器上,服务器端位于PC上。
客户端创建的Socket与服务端的ServerSocket进行交互来实现网络数据交互。
其中Socket与ServerSocket交互过程如下:
(1)服务器端程序创建一个ServerSocket,然后调用accept()方法等待客户连接
(2)客户端创建一个Socket并请求与服务器端程序建立连接。
(3)服务器端程序接受客户端的连接请求,并创建一个新的Socket与该客户端建立专线连接。
(4)建立了连接的客户端及服务器端的两个Socket在一个有服务器端程序创建的单独线程上对话,对话方式采用getInputStream()、getOutputStream()得到的输入与输出流进行数据的读取与输出。
客户端的Socket与服务器端的ServerSocket的通信如下图:
图2.1Socket与ServerSocket通信图
(5)服务器端开始等待新的连接请求,重复
(2)~(5)的过程。
在客户端程序实现了界面的显示以及与服务器端的数据交互。
在服务器端程序一共包含五个类,其名称及功能如下表所示:
StartServer
启动服务器主线程ServerThread,即启动服务器
ServerThread
服务器监听端口线程,负责创建ServerSocket以及监听是否有新客户端连接,并记录客户端连接以及需要发送的消息
ClientThread
维持服务器与单个客户端的连接线程,负责接受客户端发送来的消息
BroadCast
服务器向客户端发送广播线程,负责向客户端发送消息
DoDataBase
连接数据库,将消息拆解后按类型存放到数据库ChatDemo的messages表中
表2.1服务器端程序的四个类功能
实现通信功能的流程图如下:
图2.2系统通信功能流程图
3系统功能实现
3.1数据交互格式
对于此聊天系统,主要存在如下三类数据:
1、登陆
2、传递消息
3、退出
这三类数据都是需要向服务器端发送的数据,因为了在服务器端处理的数据不被混淆,必须对他们的数据格式进行规格化,此系统的数据规格如下图:
表3.1消息格式图
消息种类:
“L”—登陆;“S”——传递消息;“C”——退出,
目的地址:
要发往特定客户端的手机号
标识:
用来标识不同种类的信息符号其中“$$”——发送的消息标识;“##”——客户上下线标识。
源地址:
消息来源的客户端手机号码
时间:
获取到的发送消息时的时间
内容:
如果登陆则为“上线了”,如果退出则为“下线了”,如果是传递消息则为想发送的内容;
其中对于登陆和退出消息,送往服务器端进行拆分后将其目标地址置空,对于传递消息,如果目标地址和源地址相同则表示将该消息发送给所有的客户端,反之,则只是发送到这两个地址的客户端中。
3.2服务器端功能实现
3.2.1StartServer类
StartServer线程是整个服务器的主线程,当执行这个工程文件时执行这个类中的Main函数,在Main函数中创建了一个实例化了一个ServerThread线程命名为serverThread,并启动该线程,代码如下:
publicclassStartServer{
privatestaticServerThreadserverThread;
publicstaticvoidmain(String[]args){
//TODOAuto-generatedmethodstub
serverThread=newServerThread();
serverThread.start();
}
}
3.2.2ServerThread类
该类在构造函数中实例化了两个Vector数组,分别用于存放ClientThread线程和存放从客户端发送来的消息,并命名为clients和messages。
此外还对ServerSocket进行了初始化,然后启动BroadCast方法。
代码如下:
publicVector
publicVector
publicServerThread(){
clients=newVector
messages=newVector
try{
serverSocket=newServerSocket(PORT);
}catch(IOExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
try{
myIpaddress=InetAddress.getLocalHost();
}catch(UnknownHostExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
broadcast=newBroadCast(this);
broadcast.start();
}
构造方法执行后,接着执行该线程的Run()方法。
在Run()函数中用了一个死循环实现不停的对客户端的连接进行监听,一旦监听到客户端的连接请求,就获得该客户端的Socket并将其封装在ClientThread线程中,然后启动ClientThread线程并将该线程压入clients数组中以实现服务器与指定客户端或所有客服端发送数据。
此外由于clients属于临界资源,同一时刻只能允许被一个线程操作,因此使用了线程同步方法synchronized(clients)。
代码如下:
publicvoidrun(){
while(true){
try{
Socketsocket=serverSocket.accept();
System.out.println(socket.getInetAddress().getHostAddress());
ClientThreadclientThread=newClientThread(socket,this);
clientThread.start();
if(socket!
=null){
synchronized(clients){
clients.addElement(clientThread);
}
}
}catch(IOExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
3.2.3ClientThread类
当ServerThread线程开启了ClientThread线程后,通过构造函数获得了客户端的Socket套接字,然后通过Socket的getInputStream()方法和getOutputStream()方法获取输入输出流。
publicClientThread(Socketsocket,ServerThreadserverThread){
this.clientSocket=socket;
this.serverThread=serverThread;
try{
in=newDataInputStream(clientSocket.getInputStream());
out=newDataOutputStream(clientSocket.getOutputStream());
}catch(IOExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
然后执行Run()方法监听Socket是否有新的消息,然后根据消息的类别相应处理后在控制台上显示出来,并把message的第14到25的子串(username)作为ClientThread的唯一标识ID,此标识可以用来实现从一个客户端向另一指定客户端发送数据。
并利用doMsg()方法将message拆分后存放到数据库中,同时将message压入到messages消息队列中。
代码如下:
publicvoidrun(){
while(true){
try{
Stringmessage=in.readUTF();
synchronized(serverThread.messages)
{
if(message!
=null)
{
doMsg(message);
ID=message.substring(14,25);
serverThread.messages.addElement(message);
if(message.subSequence(0,1).equals("S"))
{
if(message.substring(1,12).equals(message.substring(14,25)))
{
System.out.println(message.substring(1,12)+message.substring(24));
}
else{
System.out.println("$$"+message.substring(14,25)+"对"+message.substring(1,12)+message.substring(25));
}
}
else
{
System.out.println(message.substring(12));
}
}
}
}catch(IOExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
break;
}
}
}
privatevoiddoMsg(Stringmessage){
//TODOAuto-generatedmethodstub
catgory=message.substring(0,1);
orgid=message.substring(14,25);
time=message.substring(26,34);
if(catgory.equals("S")){
goalid=message.substring(1,12);
content=message.substring(36);
}
else
{
goalid="";
content=message.substring(34);
}
try{
dodb.AddMsg(time,catgory,orgid,goalid,content);
}catch(Exceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
3.2.4BroadCast类
通过ServerThread线程调用该类后,ServerThread类通过BroadCast构造函数传给ServerThread实例,然后执行该线程的Run()方法,没循环一次线程休眠200ms,然后取出messages中尚未发送出的消息,将消息按其格式拆分后根据其意图送往各个客户端或是指定客户端,是实现群聊个私聊的功能。
同样,消息数组是临界资源,所以,用到了synchronized(serverThread.messages)方法,判断该消息为下线功能,则将根据ID删除Vector中的ClientThread线程。
源代码如下:
publicvoidrun(){
while(true){
try{
Thread.sleep(200);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
synchronized(serverThread.messages){
if(serverThread.messages.isEmpty()){
continue;
}
//获取消息队列队首消息
str=(String)this.serverThread.messages.firstElement();
}
synchronized(serverThread.clients){
System.out.println(serverThread.clients.size());
for(inti=0;i { //获取该客户端线程 clientThread=(ClientThread)serverThread.clients.elementAt(i); try{ clientThread.out.writeUTF(str); }catch(IOExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } //从消息队列中删除该消息 this.serverThread.messages.remove(str); } } } 3.2.5DoDataBase类 该类有两个方法AddMsg()和getConnection()方法,其中getConnection()方法用于获取数据库ChatDemo的连接句柄。 AddMsg()方法用于对ChatDemo中的表messages进行写操作。 实现代码如下: publicclassDoDataBase{ publicvoidAddMsg(Stringtime,StringCatgory,StringOrgID,StringGoalID,Stringcontent) throwsException{ //打开连接 Connectionconn=getConnection(); //执行操作 PreparedStatementpst=conn .prepareStatement("insertintomessagesvalues(? ? ? ? ? )"); pst.setString(1,time);//时间 pst.setString(2,Catgory);//消息种类 pst.setString(3,OrgID);//源地址 pst.setString(4,GoalID);//目的地址 pst.setString(5,content);//内容 pst.execute(); //关闭数据库 conn.close(); } privateConnectiongetConnection()throwsClassNotFoundException,SQLException{ Class.forName("net.sourceforge.jtds.jdbc.Driver"); Connectionconn=DriverManager.getConnection("jdbc: jtds: sqlserver: //localhost: 1433/ChatDemo","sa",""); returnconn; } } 3.3客户端功能实现 图3.1客户端界面 其源代码如下: publicclassChatClientActivityextendsActivityimplementsRunnable{ privateEditTextusernameEdit,ipEdit,historyEdit,messageEdit; privateButtonloginButton,leaveButton,sendButton; privateStringusername,ip,chat_txt,chat_in; publicstaticfinalintPORT=8521;//端口号 publicDataInputStreamin=null; publicDataOutputStreamout=null; publicSocketsocket; publicThreadthread; publicbooleanflag=false;//标识是否登陆,true为已登录,false为未登录 @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); usernameEdit=(EditText)findViewById(R.id.username); ipEdit=(EditText)findViewById(R.id.ip); historyEdit=(EditText)findViewById(R.id.history); messageEdit=(EditText)findViewById(R.id.message); loginButton=(Button)findViewById(R.id.LoginButton); leaveButton=(Button)findViewById(R.id.leave); sendButton=(Button)findViewById(R.id.sendButton); loginButton.setOnClickListener(listener); leaveButton.setOnClickListener(listener); sendButton.setOn
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- android 聊天室 设计