說明
這節教給大家用Android寫一個TCP客戶端程序
官方文檔
https://www.android-doc.com/reference/java/net/Socket.html
頁面
編寫連接程序
1.獲取控件
EditText editTextIPAddress,editTextPort;//輸入IP地址,端口號 Button buttonConnect;//連接按鈕 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); buttonConnect = findViewById(R.id.buttonConnect); editTextIPAddress = findViewById(R.id.editTextIPAddress); editTextPort = findViewById(R.id.editTextPort); }
2.添加網絡權限
<uses-permission android:name="android.permission.INTERNET" />
3.定義一個socket
Socket socket;
4.編寫按鈕點擊連接/斷開程序
MyHandler myHandler;//使用Handler更新控件 myHandler = new MyHandler();
buttonConnect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (buttonConnect.getText()=="連接"){ new Thread(new Runnable() { @Override public void run() { Message msg = myHandler.obtainMessage();//從消息隊列拉取個消息變量 try{ socket = new Socket(editTextIPAddress.getText().toString(),Integer.valueOf(editTextPort.getText().toString())); if(socket.isConnected()){ msg.what = 1;//設置消息變量的 what 變量值 為1 } }catch (Exception e){ msg.what = 0;//設置消息變量的 what 變量值 為0 } myHandler.sendMessage(msg);//插入消息隊列 } }).start(); } else{ try{ socket.close(); }catch (Exception e){} //關閉連接 buttonConnect.setText("連接");//按鈕顯示連接 } } });
//Handler class MyHandler extends Handler { public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 0: Toast.makeText(MainActivity.this,"連接出錯",Toast.LENGTH_SHORT).show(); break; case 1: buttonConnect.setText("斷開");//按鈕顯示斷開 break; default: break; } } }
提示:獲取IP地址和端口號,執行連接
socket = new Socket(editTextIPAddress.getText().toString(),Integer.valueOf(editTextPort.getText().toString()));
當前程序
EditText editTextIPAddress,editTextPort;//輸入IP地址,端口號 Button buttonConnect;//連接按鈕 Socket socket; MyHandler myHandler;//使用Handler更新控件 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myHandler = new MyHandler(); buttonConnect = findViewById(R.id.buttonConnect); buttonConnect.setText("連接"); editTextIPAddress = findViewById(R.id.editTextIPAddress); editTextPort = findViewById(R.id.editTextPort); buttonConnect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (buttonConnect.getText()=="連接"){ new Thread(new Runnable() { @Override public void run() { Message msg = myHandler.obtainMessage();//從消息隊列拉取個消息變量 try{ socket = new Socket(editTextIPAddress.getText().toString(),Integer.valueOf(editTextPort.getText().toString())); if(socket.isConnected()){ msg.what = 1;//設置消息變量的 what 變量值 為1 } }catch (Exception e){ msg.what = 0;//設置消息變量的 what 變量值 為0 } myHandler.sendMessage(msg);//插入消息隊列 } }).start(); } else{ try{ socket.close(); }catch (Exception e){} //關閉連接 buttonConnect.setText("連接");//按鈕顯示連接 } } }); } //Handler class MyHandler extends Handler { public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 0: Toast.makeText(MainActivity.this,"連接出錯",Toast.LENGTH_SHORT).show(); break; case 1: buttonConnect.setText("斷開");//按鈕顯示斷開 break; default: break; } } }
接收數據
1.定義 InputStream 用於獲取數據輸入流,定義一個數組用於緩存數據
InputStream inputStream;//獲取輸入流 byte[] RevBuff = new byte[1460];//緩存數據
2.定義一個函數,里面放一個任務,用於不停的接收數據
public void Recv(){ new Thread(new Runnable() { @Override public void run() { while (socket!= null && socket.isConnected()){ try{ int Len = inputStream.read(RevBuff);//獲取數據 if(Len!=-1){ Message msg = myHandler.obtainMessage();//從消息隊列拉取個消息變量 msg.what = 3;//設置消息變量的 what 變量值 為3 msg.arg1 = Len;//接收的數據個數 msg.obj = RevBuff;//傳遞數據 myHandler.sendMessage(msg);//插入消息隊列 } else{//連接異常斷開 Message msg = myHandler.obtainMessage();//從消息隊列拉取個消息變量 msg.what = 0;//設置消息變量的 what 變量值 為0 myHandler.sendMessage(msg);//插入消息隊列 break; } }catch (Exception e){//連接異常斷開 Message msg = myHandler.obtainMessage();//從消息隊列拉取個消息變量 msg.what = 0;//設置消息變量的 what 變量值 為0 myHandler.sendMessage(msg);//插入消息隊列 break; } } } }).start(); }
3.調用接收函數
4.在Handle中處理數據,把數據顯示在頁面
4.1.獲取控件
4.2.把接收的消息追加到Textview顯示
測試
1.電腦端開啟TCP服務器
2.保證手機和電腦在一個局域網內
查看自己的電腦IP
3.手機連接
接收顯示16進制數據
1.關於16進制顯示和前面的串口上位機顯示16進制數據是一樣的道理
https://www.cnblogs.com/yangfengwu/p/12382103.html
2.JAVA和C#提供的函數不一樣,java的轉換程序如下:
/** * 16進制byte轉16進制String--用空格隔開 * @param bytes * @return */ public static String byteToHexStr(byte[] bytes) { String str_msg = ""; for (int i = 0; i < bytes.length; i++){ str_msg = str_msg + String.format("%02X",bytes[i])+" "; } return str_msg; }
3.獲取16進制選擇控件
4.編寫處理函數
測試
清除接收
發送數據
1.獲取控件,定義輸出流變量
2.獲取輸出流
3.點擊發送按鈕發送發送文本框里面的數據
4.測試
發送16進制數據
1.文本框里面輸入的是字符串
假設輸入的是 55FD
那么獲取的是 "55FD"
需要轉換為 0x55 0xFD
獲取第一個字符 5 hexString.charAt(0)
轉換為 16進制形式 Character.digit(hexString.charAt(0), 16)
獲取第二個字符5 hexString.charAt(1)
轉換為 16進制形式 Character.digit(hexString.charAt(1), 16)
然后組合成一個16進制
byte data = (byte) ((Character.digit(hexString.charAt(0), 16) << 4) + Character.digit(hexString.charAt(1), 16))
2.完整的程序如下
/*** *"2B44EFD9" --> byte[]{0x2B, 0x44, 0xEF,0xD9} * @param hexString * @return */ public static byte[] hexStringToByteArray(String hexString) { StringBuilder sb = null; hexString = hexString.replaceAll(" ", ""); if ((hexString.length()%2)!=0) {//數據不是偶數 sb = new StringBuilder(hexString);//構造一個StringBuilder對象 sb.insert(hexString.length()-1, "0");//插入指定的字符串 hexString = sb.toString(); } int len = hexString.length(); byte[] bytes = new byte[len / 2]; for (int i = 0; i < len; i += 2) { if (( (hexString.charAt(i)>='0' && hexString.charAt(i)<='9') || (hexString.charAt(i)>='A' && hexString.charAt(i)<='F') || (hexString.charAt(i)>='a' && hexString.charAt(i)<='f') )&& (hexString.charAt(i+1)>='0' && hexString.charAt(i+1)<='9') || (hexString.charAt(i+1)>='A' && hexString.charAt(i+1)<='F') || (hexString.charAt(i+1)>='a' && hexString.charAt(i+1)<='f')){ // 兩位一組,表示一個字節,把這樣表示的16進制字符串,還原成一個字節 bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character .digit(hexString.charAt(i+1), 16)); } else return null; } return bytes; }
3.獲取控件
4.編寫處理程序
5.測試
補充
讓輸入的內容默認顯示在左上角
android:gravity="top"