本文主要講解安卓(Android)TCP Socket通訊客戶端(Client)和服務器(Server)Demo的實現(xiàn)(附源碼)仅醇,要注意BufferedReader的readLine()方法【((line = br.readLine()) != null)】 的阻塞問題冠桃,以及對接硬件的項目數(shù)據(jù)在十六進制&&byte&&int的轉(zhuǎn)換處理。
大坑
最近有個項目需要用到TCP Socket通訊挂签,遇到了一個大坑,所以做了這個Demo郎汪。
讀取socket輸入流的時候很多代碼都會這么寫森瘪,一般也不會有什么問題刹帕,但是readLine()方法讀取不到換行和回車時會阻塞吵血!
String line = null;
while ((line = br.readLine()) != null) {
}
readLine()是個阻塞函數(shù)谎替,可以點進去查看源碼,只有遇到換行或者回車回車符(’\n’,’\r’ 對應十六進制是 0D 0A)才會返回蹋辅,而有些模塊返回給你的數(shù)據(jù)不帶這兩個結(jié)束符钱贯,所以導致阻塞,程序不能走下去侦另。這種情況一般如果模塊那邊愿意修改加上結(jié)束符秩命,那就沒問題。如果模塊那邊又不方便改褒傅,那就不能用這種方式了弃锐,得換種寫法。
調(diào)試工具
調(diào)試的實時我們可以借助一些PC端的工具殿托,TCP調(diào)試助手霹菊、TCP測試工具類似的,度娘下很多支竹,操作也是傻瓜式的旋廷,填寫IP和端口然后建立或者連接。
Demo演示及實現(xiàn)
廢話少說礼搁,直接 進入今天的主題饶碘,下面就看看如何在Android上利用TCP/IP協(xié)議使用Socket與Server進行通訊吧!
一叹坦、權(quán)限
<uses-permission android:name="android.permission.INTERNET"/>
二熊镣、服務端實現(xiàn)卑雁,簡單來說就3步
1募书、 創(chuàng)建ServerSocket ,監(jiān)聽端口,等待客戶端Socket連接
2测蹲、從Socket里獲取的客戶端發(fā)來的消息
3莹捡、通過Socket給客戶端發(fā)消息
核心代碼如下
class ServerSocketThread extends Thread {
@Override
public void run() {
try {
// 創(chuàng)建ServerSocket
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("--開啟服務器,監(jiān)聽端口 9999--");
// 監(jiān)聽端口扣甲,等待客戶端連接
while (true) {
System.out.println("--等待客戶端連接--");
Socket socket = serverSocket.accept(); //等待客戶端連接
System.out.println("得到客戶端連接:" + socket);
startReader(socket);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 從參數(shù)的Socket里獲取消息
*/
private static void startReader(final Socket mSocket) {
new Thread(){
@Override
public void run() {
try {
// 獲取讀取流
BufferedReader in = new BufferedReader(new InputStreamReader(mSocket.getInputStream(),"utf-8"))
String line="";
while ((line = in.readLine()) != null) {// 讀取數(shù)據(jù)
System.out.println("*等待客戶端輸入*");
System.out.println("獲取到客戶端的信息:" + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
//通過socket來給客戶端發(fā)送消息
private void serverSendMessage(String mServerSendMessage) {
new Thread() {
@Override
public void run() {
PrintWriter out;
try {
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream())), true);
out.println(mServerSendMessage);
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
三篮赢、客戶端實現(xiàn),跟服務器端流程類似
1琉挖、與服務器建立Socket連接
2启泣、獲取到輸入輸出流
3、收/發(fā)送消息
//與服務器建立連接
Socket mClientSocket = new Socket(mClientIp, mClientPort);
//從socket獲取輸入輸出流
BufferedReader mClientIn = new BufferedReader(new InputStreamReader(mClientSocket.getInputStream()));
PrintWriter mClientOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mClientSocket.getOutputStream())), true);
//監(jiān)聽服務端下發(fā)的消息
String clientReceiverMessage;
if ((clientReceiverMessage = mClientIn.readLine()) != null) {
if (mOnConnectListener != null) {
mOnConnectListener.onMessage(clientReceiverMessage);
}
}
//給服務端發(fā)消息
mClientOut.println(mClientSendMessage);
代碼封裝Listener接口
在實際開發(fā)過程中示辈,我們一般會把Socket這塊封裝起來寥茫,然后對外設(shè)置Listener接口,在其它模塊里處理業(yè)務邏輯矾麻,也有的需要處理多個socket連接和通訊纱耻,
服務器端代碼實現(xiàn)示例
public class TcpServer {
private static final String TAG = "TcpServer";
private static TcpServer mTcpServer = new TcpServer();
private OnListener mOnListener;
private ServerSocketThread mServerSocketThread;
public static TcpServer getInstance() {
return mTcpServer;
}
public void setOnListener(OnListener onListener) {
mOnListener = onListener;
}
public interface OnListener {
void onStart();
void onNewClient(String serverIp, String clientIp, int count);
void onError(Throwable e, String message);
void onMessage(String ip, String message);
void onAutoReplyMessage(String ip, String message);
void onClientDisConnect(String ip);
void onConnectTimeOut(String ip);
}
public void setPort(int port) {
mServerPort = port;
}
………………………………
………………………………
………………………………
}
十六進制收發(fā)處理
對接硬件的項目通訊協(xié)議有可能是用十六進制的芭梯,所以數(shù)據(jù)要在字符串\byte\int 十六進制轉(zhuǎn)換,不過通訊部分本質(zhì)一樣弄喘,代碼如下
//十六進制 發(fā)送
try {
//byte[] msg = {(byte) 0xaa,(byte) 0xbb,(byte) 0x0d,(byte) 0x0a};
byte[] msg = IntByteStringHexUtil.hexStrToByteArray("AABB0D0A");
OutputStream socketWriter = socket.getOutputStream();
socketWriter.write(msg);
} catch (IOException e) {
e.printStackTrace();
}
//十六進制 接收
InputStream socketReader = socket.getInputStream();
byte buf[] = new byte[1024];
int len = socketReader.read(buf);
byte data[] = new byte[len];
System.arraycopy(buf, 0, data, 0, len);
logClient(len+","+IntByteStringHexUtil.byteArrayToHexStr(data));
Demo源碼下載地址
源碼也都放在CSDN上了玖喘,有需要的可以借鑒