Android socket 通信
安卓編寫Socket客戶端,實現連接Socket服務端通信。
創建Socket連接並獲取服務端數據
先創建幾個全局變量吧
private BufferedWriter writer = null;
Socket socket;
創建Socket
// 填好IPV4的IP地址和端口,服務端會提供,問服務端要
socket = new Socket("192.168.1.156", 1234);
// 下面三句照抄就行
writer = new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream()));
InputStream inputStream = socket.getInputStream();
DataInputStream input = new DataInputStream(inputStream);
// 創建一個字節數組用來接收服務端發來的字節流,多大自己說了算
byte[] b = new byte[100000];
// 寫一個死循環,不停的接收服務端發來的數據
while (true) {
// 將數據讀入字節數組,返回長度
int length = input.read(b);
// 如果服務端沒發數據就return不在往下執行,繼續讀數據
if (length <= 0) return;
// 如果服務端發的數據不為空,則把字節數組轉成字符串
msg = new String(b, 0, length, "gb2312");
// 后邊就可以調用數據解析的方法
....
}
一般的通訊格式都是Json的,查一下把json格式的字符串轉換成json對象然后根據key值獲取value的代碼:
// 其中,data是json格式的字符串,轉換成了jsonObject對象
JSONObject jsonObject = new JSONObject(data);
// 獲取jsonObject對象的device_id值,當然device_id是String類型的,如果是int就用int
String i = jsonObject.getString("device_id");
發送數據給服務端
發送數據給服務端的前提是已經完成了Socket連接
// 首先判斷一下socket是不是已經創建連接了,如果沒有就不管它
if (socket == null) return;
// str是准備發給服務端的字符串
writer.write(str);
// 發出去(留坑,繼續看完)
writer.flush();
這就完成了Android編寫Socket與服務端通信的功能。但是這個Socket IPV4的地址可以,IPV6的地址我沒試過,聽說好像有點問題,但是大部分都用IPV4,如果真的用到IPV6的話,再百度!
糾錯
問題來咯!!!
我遇到的大坑!
在很早之前我開發的時候上面的操作編寫方式完全沒問題!
但是,昨天我寫的時候發現會報錯!報錯在 writer.flush() 這個地方。
百度之后發現:
老版的android不會有問題,但是新版本的android(好像是sdk10以上)已經不允許在UI線程(主線程)中發起網絡請求了,會拋出NetWorkInUIThreadException。
所以說給服務端發送數據的時候需要寫到子線程里。
new Thread(new Runnable() {
@Override
public void run() {
// 首先判斷一下socket是不是已經創建連接了,如果沒有就不管它
if (socket == null) return;
// str是准備發給服務端的字符串
writer.write("我是Android客戶端發的數據");
// 發出去
writer.flush();
}
}).start();
這樣就開一個子線程,在子線程中編寫發送數據的代碼或調用發送數據的方法就沒問題了!
留坑!
生命不息,留坑不止!!
如果我們把發送數據的代碼封裝成一個方法,並且發送的數據需要方法傳參,比如:
public void sendData(String str){
new Thread(new Runnable() {
@Override
public void run() {
// 首先判斷一下socket是不是已經創建連接了,如果沒有就不管它
if (socket == null) return;
// str是准備發給服務端的字符串,會報錯,傳進來的參數子線程進不來
writer.write(str);
// 發出去
writer.flush();
}
}).start();
}
發現父線程傳進的參數,子線程讀不到,我郁悶了好久,自己寫了個內部類解決了。
/**
* 接口類,實現主線程向子線程傳值
*/
class sendData implements Runnable {
String str;
public sendValueToServer(String str) {
this.str = str;
}
@Override
public void run() {
try {
// 如果socket連接失敗,則停止執行
if (socket == null) return;
// 發送傳進來的值
writer.write(str);
// 發出去
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
然后在需要發送的地方寫:
new Thread(new sendData ("傳值數據")).start();
完成!哈哈哈,刺激!