Android socket编程 以非阻塞I.docx
《Android socket编程 以非阻塞I.docx》由会员分享,可在线阅读,更多相关《Android socket编程 以非阻塞I.docx(17页珍藏版)》请在冰豆网上搜索。
Androidsocket编程以非阻塞I
Androidsocket编程以非阻塞I/O服务器及Service为例
来源:
中国手机开发网2010年01月25日字体:
[小大]点击推荐给好友
关键字:
之前采用聊天敲门的方式来介绍Socket通信,有两个不足的地方,
1.服务器会造成IO的阻塞
即服务器一旦执行server.accept();
将一直处于阻塞状态,直到有客户端请求连接。
2.服务器端没有建立用户列表,无法将某一客户端发送的消息广播给所有正在连接的客户端。
就好象是一个人自说自话,自己发送给客户端,自己接收服务器返回的消息。
基于以上两点,我改进了我的程序。
服务器端的改进:
1.通过采用socketchannel的非阻塞方式进行通信
2.建立Userlist客户端的哈希表,存储已连接客户端的ip地址和服务器为其分发的socketchannel
客户端的改进:
1.采用Service与服务器端进行连接,发送数据,实时监听服务器返回的数据。
流程图:
需要改进的地方
服务器端:
1.当一个客户端断开连接以后,另一个客户端在收到消息之前也断开连接,而此时服务器正在向客户端发送消息,
因此,服务器的Thread.sleep时间不能太长,但也不能太短,因为考虑到服务器的负荷问题。
2.服务器容错处理机制需要改进。
客户端:
1.将Notificationbar改为其他更为直观方式刷新显示。
2.容错处理机制的处理。
下面是效果图:
服务器端:
dos客户端:
Android客户端:
效果图的意思是,Android的客户端通过绑定Service与服务器端进行了连接,并发送消息。
服务器向所有正在连接的客户端广播消息。
之后,Dos终端也进行连接,并发送消息,服务器接到消息后向所有正在连接的客户端广播消息(其中包括在线的android手机)
第1页第2页第3页第4页第5页第6页
之前采用聊天敲门的方式来介绍Socket通信,有两个不足的地方,
1.服务器会造成IO的阻塞
即服务器一旦执行server.accept();
将一直处于阻塞状态,直到有客户端请求连接。
2.服务器端没有建立用户列表,无法将某一客户端发送的消息广播给所有正在连接的客户端。
就好象是一个人自说自话,自己发送给客户端,自己接收服务器返回的消息。
基于以上两点,我改进了我的程序。
服务器端的改进:
1.通过采用socketchannel的非阻塞方式进行通信
2.建立Userlist客户端的哈希表,存储已连接客户端的ip地址和服务器为其分发的socketchannel
客户端的改进:
1.采用Service与服务器端进行连接,发送数据,实时监听服务器返回的数据。
流程图:
需要改进的地方
服务器端:
1.当一个客户端断开连接以后,另一个客户端在收到消息之前也断开连接,而此时服务器正在向客户端发送消息,
因此,服务器的Thread.sleep时间不能太长,但也不能太短,因为考虑到服务器的负荷问题。
2.服务器容错处理机制需要改进。
客户端:
1.将Notificationbar改为其他更为直观方式刷新显示。
2.容错处理机制的处理。
下面是效果图:
服务器端:
dos客户端:
Android客户端:
效果图的意思是,Android的客户端通过绑定Service与服务器端进行了连接,并发送消息。
服务器向所有正在连接的客户端广播消息。
之后,Dos终端也进行连接,并发送消息,服务器接到消息后向所有正在连接的客户端广播消息(其中包括在线的android手机)
第1页第2页第3页第4页第5页第6页
接上页
源代码如下:
Server端:
packagecom.android.Yao;
importjava.io.*;
importjava.nio.*;
importjava.nio.channels.*;
import.*;
importjava.util.*;
importjava.nio.charset.*;
importjava.lang.*;
publicclassYaoChatServer
{
publicSelectorsel=null;
publicServerSocketChannelserver=null;
publicSocketChannelsocket=null;
publicintthisport=4900;
privateStringresult=null;
privateHashtableuserlists;
privateSocketChannelreadingsocket=null;
publicYaoChatServer()
{
System.out.println("Insidestartserver");
}
publicYaoChatServer(intport)
{
System.out.println("Insidestartserver");
thisport=port;
}
publicvoidinitializeOperations()throwsIOException,UnknownHostException
{
System.out.println("Insideinitialization");
sel=Selector.open();
server=ServerSocketChannel.open();
server.configureBlocking(false);
InetAddressia=InetAddress.getLocalHost();
InetSocketAddressisa=newInetSocketAddress(ia,thisport);
server.socket().bind(isa);
userlists=newHashtable();
}
publicvoidstartServer()throwsIOException
{
initializeOperations();
server.register(sel,SelectionKey.OP_ACCEPT);
while(sel.select()>0)
{
SetreadyKeys=sel.selectedKeys();
Iteratorit=readyKeys.iterator();
while(it.hasNext())
{
SelectionKeykey=(SelectionKey)it.next();
it.remove();
if(key.isAcceptable())
{
ServerSocketChannelssc=(ServerSocketChannel)key.channel();
socket=(SocketChannel)ssc.accept();
socket.configureBlocking(false);
Stringsocketname=socket.socket().getRemoteSocketAddress().toString();
socket.register(sel,SelectionKey.OP_WRITE);
userlists.put(socketname,socket);
System.out.println(socketname+"isconnected!
");
}
if(key.isWritable()){
readingsocket=(SocketChannel)key.channel();
Stringret=readMessage(readingsocket);
if(ret.equalsIgnoreCase("@@@@@isgoingtosaygoodbye!
"))
{
key.cancel();
readingsocket.close();
userlists.remove(readingsocket.socket().getRemoteSocketAddress().toString());
System.out.println("sendservermsg:
"+ret.replace("@@@@@",readingsocket.socket().getRemoteSocketAddress().toString()));
sendMessage(ret.replace("@@@@@",readingsocket.socket().getRemoteSocketAddress().toString()));
}
elseif(ret.length()>0){
System.out.println("sendservermsg:
"+ret);
sendMessage(ret);
}
}
}
}
}
publicvoidsendMessage(Stringmsg)throwsIOException
{
ByteBufferbuffer=ByteBuffer.allocate(1024);
buffer=ByteBuffer.wrap(msg.getBytes());
//ByteBufferbuffer=ByteBuffer.wrap(msg.getBytes("UTF-8"));
Collectionchannels=userlists.values();
SocketChannelsc;
for(Objecto:
channels){
sc=(SocketChannel)o;
sc.write(buffer);
buffer.flip();
try{
Thread.sleep(500);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
publicStringreadMessage(SocketChannelsc)
{
intnBytes=0;
ByteBufferbuf=ByteBuffer.allocate(1024);
try{
nBytes=sc.read(buf);
buf.flip();
Charsetcharset=Charset.forName("UTF-8");
CharsetDecoderdecoder=charset.newDecoder();
CharBuffercharBuffer=decoder.decode(buf);
result=charBuffer.toString();
}catch(IOExceptione){
result="@@@@@isgoingtosaygoodbye!
";
}
returnresult;
}
publicstaticvoidmain(Stringargs[])
{
YaoChatServernb=newYaoChatServer();
try
{
nb.startServer();
}
catch(IOExceptione)
{
e.printStackTrace();
System.exit(-1);
}
}
}
Android客户端的Service类:
packagecom.android.Yao;
importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
import.InetSocketAddress;
importjava.nio.ByteBuffer;
importjava.nio.CharBuffer;
importjava.nio.channels.SocketChannel;
importjava.nio.charset.CharacterCodingException;
importjava.nio.charset.Charset;
importjava.nio.charset.CharsetDecoder;
importjava.util.Collection;
importandroid.app.Notification;
importandroid.app.NotificationManager;
importandroid.app.PendingIntent;
importandroid.app.Service;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.os.Binder;
importandroid.os.IBinder;
publicclassReceiveMessageextendsService{
privateSocketChannelclient=null;
privateInetSocketAddressisa=null;
privateStringmessage="";
publicvoidonCreate(){
super.onCreate();
ConnectToServer();
StartServerListener();
}
publicvoidonDestroy(){
super.onDestroy();
DisConnectToServer();
}
publicvoidonStart(Intentintent,intstartId){
super.onStart(intent,startId);
}
/*
*IBinder方法,LocalBinder类,mBinder接口这三项用于
*Activity进行Service的绑定,点击发送消息按钮之后触发绑定
*并通过Intent将Activity中的EditText的值
*传送到Service中向服务器发送
*
**/
publicIBinderonBind(Intentintent){
message=intent.getStringExtra("chatmessage");
if(message.length()>0)
{
SendMessageToServer(message);
}
returnmBinder;
}
publicclassLocalBinderextendsBinder{
ReceiveMessagegetService(){
returnReceiveMessage.this;
}
}
privatefinalIBindermBinder=newLocalBinder();
//用于链接服务器端
publicvoidConnectToServer()
{
try{
client=SocketChannel.open();
isa=newInetSocketAddress("192.168.0.107",4900);
client.connect(isa);
client.configureBlocking(false);
}catch(IOExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
//断开与服务器端的链接
publicvoidDisConnectToServer()
{
try{
client.close();
}catch(IOExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
//启动服务器端的监听线程,从Server端接收消息
publicvoidStartServerListener()
{
ServerListenera=newServerListener();
a.start();
}
//向Server端发送消息
publicvoidSendMessageToServer(Stringmsg)
{
try
{
ByteBufferbytebuf=ByteBuffer.allocate(1024);
bytebuf=ByteBuffer.wrap(msg.getBytes("UTF-8"));
client.write(bytebuf);
bytebuf.flip();
}
catch(IOExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
privatevoidshownotification(Stringtab)
{
NotificationManagerbarmanager=(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
Notificationmsg=newNotification(android.R.drawable.stat_notify_chat,"AMessageComing!
",System.currentTimeMillis());
PendingIntentcontentIntent=PendingIntent.getActivity(this,0,newIntent(this,YaoChatRoomAndroid.class),PendingIntent.FLAG_ONE_SHOT);
msg.setLatestEventInfo(this,"Message","Message:
"+tab,contentIntent);
barmanager.notify(0,msg);
}
privateclassServerListenerextendsThread
{
publicvoidrun(){
try{
//无线循环,监听服务器,如果有不为空的信息送达,则更新Activity的UI
while(true)
{
ByteBufferbuf=ByteBuffer.allocate(1024);
client.read(buf);
buf.flip();
Charsetcharset=Charset.forName("UTF-8");
CharsetDecoderdecoder=charset.newDecoder();
CharBuffercharBuffer;
charBuffer=decoder.decode(buf);
Stringresult=charBuffer.toString();
if(result.length()>0)
shownotification(result);
}
}
catch(CharacterCodingExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
catch(IOExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
}