Android 通過Socket 和服務器通訊,是一種比較常用的通訊方式,時間比較緊,說下大致的思路,希望能幫到使用socket 進行通信的人
(1)開啟一個線程發送消息 SocketOutputThread
消息是放在隊列裡的,當有消息後,進入隊列,線程喚醒,發送消息,並反饋發送是否成功的回調
(2)開啟一個線程接受服務器消息 SocketInputThread
為了防止一直收數據,浪費電池的電,采用NIO的方式讀socket的數據,這個是本文的關鍵
(3)開啟一個線程,做心跳,防止socket連接終斷 , SocketHeartThread
(4)構建 SocketThreadManager對以上三個thread進行管理
(5)構建 TCPClient 發送socket消息
在NIO的方式實現TCP,特別是在接收服務器的數據,不用寫個線程定時去讀了。
本文地址(http://www.cnblogs.com/likwo/p/3641135.html)
DEMO 截圖
主要代碼如下,詳細代碼在附件裡。
SocketOutPutThread 類
復制代碼
package com.example.socketblockdemo;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
/**
* 客戶端寫消息線程
*
* @author way
*
*/
public class SocketOutputThread extends Thread
{
private boolean isStart = true;
private static String tag = "socketOutputThread";
private List<MsgEntity> sendMsgList;
public SocketOutputThread( )
{
sendMsgList = new CopyOnWriteArrayList<MsgEntity>();
}
public void setStart(boolean isStart)
{
this.isStart = isStart;
synchronized (this)
{
notify();
}
}
// 使用socket發送消息
public boolean sendMsg(byte[] msg) throws Exception
{
if (msg == null)
{
CLog.e(tag, "sendMsg is null");
return false;
}
try
{
TCPClient.instance().sendMsg(msg);
} catch (Exception e)
{
throw (e);
}
return true;
}
// 使用socket發送消息
public void addMsgToSendList(MsgEntity msg)
{
synchronized (this)
{
this.sendMsgList.add(msg);
notify();
}
}
@Override
public void run()
{
while (isStart)
{
// 鎖發送list
synchronized (sendMsgList)
{
// 發送消息
for (MsgEntity msg : sendMsgList)
{
Handler handler = msg.getHandler();
try
{
sendMsg(msg.getBytes());
sendMsgList.remove(msg);
// 成功消息,通過hander回傳
if (handler != null)
{
Message message = new Message();
message.obj = msg.getBytes();
message.what =1;
handler.sendMessage(message);
// handler.sendEmptyMessage(1);
}
} catch (Exception e)
{
e.printStackTrace();
CLog.e(tag, e.toString());
// 錯誤消息,通過hander回傳
if (handler != null)
{
Message message = new Message();
message.obj = msg.getBytes();
message.what = 0;;
handler.sendMessage(message);
}
}
}
}
synchronized (this)
{
try
{
wait();
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}// 發送完消息後,線程進入等待狀態
}
}
}
}
復制代碼
SocketInputThread
復制代碼
package com.example.socketblockdemo;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ClosedSelectorException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import android.content.Intent;
import android.text.TextUtils;
/**
* 客戶端讀消息線程
*
* @author way
*
*/
public class SocketInputThread extends Thread
{
private boolean isStart = true;
private static String tag = "socket";
// private MessageListener messageListener;// 消息監聽接口對象
public SocketInputThread()
{
}
public void setStart(boolean isStart)
{
this.isStart = isStart;
}
@Override
public void run()
{
while (isStart)
{
// 手機能聯網,讀socket數據
if (NetManager.instance().isNetworkConnected())
{
if (!TCPClient.instance().isConnect())
{
CLog.e(tag, "TCPClient connet server is fail read thread sleep second" +Const.SOCKET_SLEEP_SECOND );
try
{
sleep(Const.SOCKET_SLEEP_SECOND * 1000);
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
readSocket();
// 如果連接服務器失敗,服務器連接失敗,sleep固定的時間,能聯網,就不需要sleep
CLog.e("socket","TCPClient.instance().isConnect() " + TCPClient.instance().isConnect() );
}
}
}
public void readSocket()
{
Selector selector = TCPClient.instance().getSelector();
if (selector == null)
{
return;
}
try
{
// 如果沒有數據過來,一直柱塞
while (selector.select() > 0)
{
for (SelectionKey sk : selector.selectedKeys())
{
// 如果該SelectionKey對應的Channel中有可讀的數據
if (sk.isReadable())
{
// 使用NIO讀取Channel中的數據
SocketChannel sc = (SocketChannel) sk.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
try
{
sc.read(buffer);
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
// continue;
}
buffer.flip();
String receivedString = "";
// 打印收到的數據
try
{
receivedString = Charset.forName("UTF-8")
.newDecoder().decode(buffer).toString();
CLog.e(tag, receivedString);
Intent i = new Intent(Const.BC);
i.putExtra("response", receivedString);
MainActivity.s_context.sendBroadcast(i );
} catch (CharacterCodingException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
buffer.clear();
buffer = null;
try
{
// 為下一次讀取作准備
sk.interestOps(SelectionKey.OP_READ);
// 刪除正在處理的SelectionKey
selector.selectedKeys().remove(sk);
} catch (CancelledKeyException e)
{
e.printStackTrace();
}
}
}
}
// selector.close();
// TCPClient.instance().repareRead();
} catch (IOException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ClosedSelectorException e2)
{
}
}
}
復制代碼
SocketHeartHread 心態類
復制代碼
package com.example.socketblockdemo;
import java.io.IOException;
import android.text.TextUtils;
class SocketHeartThread extends Thread
{
boolean isStop = false;
boolean mIsConnectSocketSuccess = false;
static SocketHeartThread s_instance;
private TCPClient mTcpClient = null;
static final String tag = "SocketHeartThread";
public static synchronized SocketHeartThread instance()
{
if (s_instance == null)
{
s_instance = new SocketHeartThread();
}
return s_instance;
}
public SocketHeartThread()
{
TCPClient.instance();
// 連接服務器
// mIsConnectSocketSuccess = connect();
}
public void stopThread()
{
isStop = true;
}
/**
* 連接socket到服務器, 並發送初始化的Socket信息
*
* @return
*/
private boolean reConnect()
{
return TCPClient.instance().reConnect();
}
public void run()
{
isStop = false;
while (!isStop)
{
// 發送一個心跳包看服務器是否正常
boolean canConnectToServer = TCPClient.instance().canConnectToServer();
if(canConnectToServer == false){
reConnect();
}
try
{
Thread.sleep(Const.SOCKET_HEART_SECOND * 1000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
復制代碼
線程管理類
復制代碼
package com.example.socketblockdemo;
import android.os.Handler;
import android.text.TextUtils;
public class SocketThreadManager
{
private static SocketThreadManager s_SocketManager = null;
private SocketInputThread mInputThread = null;
private SocketOutputThread mOutThread = null;
private SocketHeartThread mHeartThread = null;
// 獲取單例
public static SocketThreadManager sharedInstance()
{
if (s_SocketManager == null)
{
s_SocketManager = new SocketThreadManager();
s_SocketManager.startThreads();
}
return s_SocketManager;
}
// 單例,不允許在外部構建對象
private SocketThreadManager()
{
mHeartThread = new SocketHeartThread();
mInputThread = new SocketInputThread();
mOutThread = new SocketOutputThread();
}
/**
* 啟動線程
*/
private void startThreads()
{
mHeartThread.start();
mInputThread.start();
mInputThread.setStart(true);
mOutThread.start();
mInputThread.setStart(true);
// mDnsthread.start();
}
/**
* stop線程
*/
public void stopThreads()
{
mHeartThread.stopThread();
mInputThread.setStart(false);
mOutThread.setStart(false);
}
public static void releaseInstance()
{
if (s_SocketManager != null)
{
s_SocketManager.stopThreads();
s_SocketManager = null;
}
}
public void sendMsg(byte [] buffer, Handler handler)
{
MsgEntity entity = new MsgEntity(buffer, handler);
mOutThread.addMsgToSendList(entity);
}
}