Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 初級開發 >> Android socket編程 以非阻塞I/O服務器及Service為例

Android socket編程 以非阻塞I/O服務器及Service為例

編輯:初級開發

之前采用聊天敲門的方式來介紹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手機)

源代碼如下:

Server端:

package com.android.Yao;

import Java.io.*;

import Java.nio.*;

import Java.nio.channels.*;

import Java.Net.*;

import Java.util.*;

import Java.nio.charset.*;

import Java.lang.*;

public class YaoChatServer

{

public Selector sel = null;

public ServerSocketChannel server = null;

public SocketChannel socket = null;

public int thisport = 4900;

private String result = null;

private Hashtable userlists ;

private SocketChannel readingsocket = null;

public YaoChatServer()

{

System.out.println("Inside startserver ");

}

public YaoChatServer(int port)

{

System.out.println("Inside startserver ");

thisport = port;

}

public void initializeOperations() throws IOException,UnknownHostException

{

System.out.println("Inside initialization ");

sel = Selector.open();

server = ServerSocketChannel.open();

server.configureBlocking(false);

InetAddress ia = InetAddress.getLocalHost();

InetSocketAddress isa = new InetSocketAddress(ia,thisport);

server.socket().bind(isa);

userlists = new Hashtable();

}

public void startServer() throws IOException

{

initializeOperations();

server.register(sel, SelectionKey.OP_ACCEPT);

while (sel.select() > 0 )

{

Set readyKeys = sel.selectedKeys();

Iterator it = readyKeys.iterator();

while(it.hasNext())

{

SelectionKey key = (SelectionKey)it.next();

it.remove();

if (key.isAcceptable())

{

ServerSocketChannel ssc = (ServerSocketChannel) key.channel();

socket = (SocketChannel) ssc.accept();

socket.configureBlocking(false);

String socketname = socket.socket().getRemoteSocketAddress().toString();

socket.register(sel, SelectionKey.OP_WRITE);

userlists.put(socketname,socket);

System.out.println(socketname +" is connected!");

}

if (key.isWritable()) {

readingsocket =(SocketChannel)key.channel();

String ret=readMessage(readingsocket);

if (ret.equalsIgnoreCase("@@@@@ is going to say goodbye!"))

{

key.cancel();

readingsocket.close();

userlists.remove(readingsocket.socket().getRemoteSocketAddress().toString());

System.out.println("send server msg:"+ret.replace("@@@@@", readingsocket.socket().getRemoteSocketAddress().toString()));

sendMessage(ret.replace("@@@@@", readingsocket.socket().getRemoteSocketAddress().toString()));

}

else if (ret.length() > 0 ) {

System.out.println("send server msg:"+ret);

sendMessage(ret);

}

}

}

}

}

public void sendMessage(String msg) throws IOException

{

ByteBuffer buffer = ByteBuffer.allocate(1024);

buffer = ByteBuffer.wrap(msg.getBytes());

// ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes("UTF-8"));

Collection channels = userlists.values();

SocketChannel sc;

for(Object o:channels){

sc = (SocketChannel)o;

sc.write(buffer);

buffer.flip();

try {

Thread.sleep(500);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

public String readMessage(SocketChannel sc)

{

int nBytes = 0;

ByteBuffer buf = ByteBuffer.allocate(1024);

try {

nBytes = sc.read(buf);

buf.flip();

Charset charset = Charset.forName("UTF-8");

CharsetDecoder decoder = charset.newDecoder();

CharBuffer charBuffer = decoder.decode(buf);

result = charBuffer.toString();

} catch (IOException e) {

result = "@@@@@ is going to say goodbye!";

}

return result;

}

public static void main(String args[])

{

YaoChatServer nb = new YaoChatServer();

try

{

nb.startServer();

}

catch (IOException e)

{

e.printStackTrace();

System.exit(-1);

}

}

}

android客戶端的Service類:

package com.android.Yao;

import Java.io.BufferedReader;

import Java.io.IOException;

import Java.io.InputStreamReader;

import Java.Net.InetSocketAddress;

import Java.nio.ByteBuffer;

import Java.nio.CharBuffer;

import Java.nio.channels.SocketChannel;

import Java.nio.charset.CharacterCodingException;

import Java.nio.charset.Charset;

import Java.nio.charset.CharsetDecoder;

import Java.util.Collection;

import android.app.Notification;

import android.app.NotificationManager;

import android.app.PendingIntent;

import android.app.Service;

import android.content.Context;

import android.content.Intent;

import android.os.Binder;

import android.os.IBinder;

public class ReceiveMessage extends Service{

private SocketChannel clIEnt = null;

private InetSocketAddress isa = null;

private String message="";

public void onCreate() {

super.onCreate();

ConnectToServer();

StartServerListener();

}

public void onDestroy() {

super.onDestroy();

DisConnectToServer();

}

public void onStart(Intent intent, int startId) {

super.onStart(intent, startId);

}

/*

* IBinder方法 , LocalBinder 類,mBinder接口這三項用於

* Activity進行Service的綁定,點擊發送消息按鈕之後觸發綁定

* 並通過Intent將Activity中的EditText的值

* 傳送到Service中向服務器發送

*

* */

public IBinder onBind(Intent intent) {

message = intent.getStringExtra("chatmessage");

if(message.length()>0)

{

SendMessageToServer(message);

}

return mBinder;

}

public class LocalBinder extends Binder {

ReceiveMessage getService() {

return ReceiveMessage.this;

}

}

private final IBinder mBinder = new LocalBinder();

//用於鏈接服務器端

public void ConnectToServer()

{

try {

clIEnt = SocketChannel.open();

isa = new InetSocketAddress("192.168.0.107",4900);

clIEnt.connect(isa);

clIEnt.configureBlocking(false);

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

//斷開與服務器端的鏈接

public void DisConnectToServer()

{

try {

clIEnt.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

//啟動服務器端的監聽線程,從Server端接收消息

public void StartServerListener()

{

ServerListener a=new ServerListener();

a.start();

}

//向Server端發送消息

public void SendMessageToServer(String msg)

{

try

{

ByteBuffer bytebuf = ByteBuffer.allocate(1024);

bytebuf = ByteBuffer.wrap(msg.getBytes("UTF-8"));

clIEnt.write(bytebuf);

bytebuf.flip();

}

catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

private void shownotification(String tab)

{

NotificationManager barmanager=(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

Notification msg=new Notification(android.R.drawable.stat_notify_chat,"A Message Coming!",System.currentTimeMillis());

PendingIntent contentIntent=PendingIntent.getActivity(this, 0, new Intent(this,YaoChatRoomandroid.class), PendingIntent.FLAG_ONE_SHOT);

msg.setLatestEventInfo(this,"Message" , "Message:"+tab, contentIntent);

barmanager.notify(0, msg);

}

private class ServerListener extends Thread

{

public void run () {

try {

//無線循環,監聽服務器,如果有不為空的信息送達,則更新Activity的UI

while(true)

{

ByteBuffer buf = ByteBuffer.allocate(1024);

clIEnt.read(buf);

buf.flip();

Charset charset = Charset.forName("UTF-8");

CharsetDecoder decoder = charset.newDecoder();

CharBuffer charBuffer;

charBuffer = decoder.decode(buf);

String result = charBuffer.toString();

if (result.length()>0)

shownotification(result);

}

}

catch (CharacterCodingException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved