【Android Socket專題】:UDP通訊客戶端app的demo的實現
Android Socket 專題:
關於UDP通訊其實可以不用多做累述,多數像我一樣的朋友在此基礎上也只是為了應用,需要了解下該瞭解的就可以了,具體的想要對這個協議研究深入的,可以自己努力!我這兒只做Android客戶端的應用實現,注意是客戶端,不是伺服器,那麼伺服器怎麼實現呢? 點選上方,已經補充!!!
規劃自己的介面的(非常簡單):
XML實現效果圖如下:
附上對應XML程式碼:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:orientation="vertical" android:layout_weight="2" tools:context="jiugaosh.com.udpdemo.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:orientation="vertical" android:layout_weight="1"> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="接收區:" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:textSize="8dp" android:id="@+id/btn_udpConn" android:text="建立連線" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:textSize="8dp" android:id="@+id/btn_udpClose" android:text="關閉連線" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:textSize="8dp" android:id="@+id/btn_CleanRecv" android:text="清除接收區" /> </LinearLayout> <TextView android:layout_width="match_parent" android:layout_weight="7" android:layout_height="0dp" android:id="@+id/txt_Recv" android:background="@drawable/border"/> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:orientation="horizontal" android:layout_weight="2"> <CheckBox android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2" android:text="Hex顯示"/> <CheckBox android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2" android:text="二進位制顯示"/> <CheckBox android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2" android:text="十進位制顯示"/> </LinearLayout> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:orientation="vertical" android:layout_weight="1"> <TextView android:layout_width="wrap_content" android:layout_height="0dp" android:layout_weight="1" android:text="傳送區:" /> <TextView android:layout_width="match_parent" android:layout_weight="7" android:background="@drawable/border" android:id="@+id/txt_Send" android:layout_height="0dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:orientation="horizontal" android:layout_weight="2"> <CheckBox android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2" android:text="Hex顯示"/> <CheckBox android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2" android:text="二進位制顯示"/> <CheckBox android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2" android:text="十進位制顯示"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:orientation="horizontal" android:layout_weight="2"> <EditText android:layout_width="0dp" android:layout_weight="5" android:id="@+id/edit_Send" android:background="@drawable/border" android:layout_height="match_parent" /> <Button android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" android:layout_gravity="right" android:id="@+id/btn_Send" android:text="傳送"/> </LinearLayout> </LinearLayout> </LinearLayout>
至此我們介面全部完成,我們開始實現對應功能!繼續向下看。
首先在寫程式碼前要說明下關鍵性的幾個類,我們完成udp客戶端其實主要就是通過這幾個類實現的:
1、DatagramSocket
2、DatagramPacket
3、InetAddress
關於這幾個類到底是什麼意思,包含了什麼資訊,大家可以自己去百度谷歌,或者直接開啟JAVA API文件檢視便知,這裡不做贅述,看具體實現。
關於UDP客戶端收發這裡,實現思路是:
啟動UDP執行緒:
1、建立DatagramSocket通訊資料報
2、建立接收事件專用DatagramPacket資料包
3、建立超時(這個和後面關閉通訊有關)
4、建立監聽接收訊息迴圈機制(接收訊息處理在此處,接收到的訊息通過
5、結束迴圈,關閉資料報。
以上為收取資訊思路,傳送資訊則為UDP執行緒中的一個方法,直接被呼叫,共享了接收塊的DatagramSocket資料報:
UDP Thread Run--->[Function方法]send(String SendMsg)
下面看具體程式碼實現:
package jiugaosh.com.udpdemo; import android.content.Intent; import android.util.Log; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; /** * Created by lenovo on 2016/2/23. */ public class UDPClient implements Runnable{ final static int udpPort = 9999; final static String hostIp = "192.168.1.4"; private static DatagramSocket socket = null; private static DatagramPacket packetSend,packetRcv; private boolean udpLife = true; //udp生命執行緒 private byte[] msgRcv = new byte[1024]; //接收訊息 public UDPClient(){ super(); } //返回udp生命執行緒因子是否存活 public boolean isUdpLife(){ if (udpLife){ return true; } return false; } //更改UDP生命執行緒因子 public void setUdpLife(boolean b){ udpLife = b; } //傳送訊息 public String send(String msgSend){ InetAddress hostAddress = null; try { hostAddress = InetAddress.getByName(hostIp); } catch (UnknownHostException e) { Log.i("udpClient","未找到伺服器"); e.printStackTrace(); } /* try { socket = new DatagramSocket(); } catch (SocketException e) { Log.i("udpClient","建立傳送資料報失敗"); e.printStackTrace(); }*/ packetSend = new DatagramPacket(msgSend.getBytes() , msgSend.getBytes().length,hostAddress,udpPort); try { socket.send(packetSend); } catch (IOException e) { e.printStackTrace(); Log.i("udpClient","傳送失敗"); } // socket.close(); return msgSend; } @Override public void run() { try { socket = new DatagramSocket(); socket.setSoTimeout(3000);//設定超時為3s } catch (SocketException e) { Log.i("udpClient","建立接收資料報失敗"); e.printStackTrace(); } packetRcv = new DatagramPacket(msgRcv,msgRcv.length); while (udpLife){ try { Log.i("udpClient", "UDP監聽"); socket.receive(packetRcv); String RcvMsg = new String(packetRcv.getData(),packetRcv.getOffset(),packetRcv.getLength()); //將收到的訊息發給主介面 Intent RcvIntent = new Intent(); RcvIntent.setAction("udpRcvMsg"); RcvIntent.putExtra("udpRcvMsg", RcvMsg); MainActivity.context.sendBroadcast(RcvIntent); Log.i("Rcv",RcvMsg); }catch (IOException e){ e.printStackTrace(); } } Log.i("udpClient","UDP監聽關閉"); socket.close(); } }
至此UDP核心程式碼全部部署完成,其中包含了少許其他功能, 如傳送給主介面訊息程式碼等,不影響,有不需要的可以自行刪除。其中如果想傳送訊息,那麼呼叫其中的send方法即可。
下面則是主介面程式碼實現,我的實現思路如下(各有各的實現方法,如果您有更好的,如果願意請告訴我,我十分願意學習):
MainActivity介面:
Handler類(主要處理UI更新事件)
OnCreate(繫結控制元件,事件監聽,註冊BroadcastReceiver等)
MyButtonClick類(處理各按鈕事件)
BroadcastReceiver(廣播接收器)
至於裡面各自類包含的小邏輯,就不多講了,看demo可以很快便知道如何使用對應了。
話不多說,放碼過來:
package jiugaosh.com.udpdemo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.os.Handler;
import java.lang.ref.WeakReference;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends AppCompatActivity {
TextView txt_Recv,txt_Send;
Button btn_CleanRecv,btn_Send,btn_UdpConn,btn_UdpClose;
EditText edit_Send;
private UDPClient client = null;
public static Context context;
private final MyHandler myHandler = new MyHandler(this);
private StringBuffer udpRcvStrBuf=new StringBuffer(),udpSendStrBuf=new StringBuffer();
MyBtnClick myBtnClick = new MyBtnClick();
private class MyHandler extends Handler{
private final WeakReference<MainActivity> mActivity;
public MyHandler(MainActivity activity){
mActivity = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1:
udpRcvStrBuf.append(msg.obj.toString());
txt_Recv.setText(udpRcvStrBuf.toString());
break;
case 2:
udpSendStrBuf.append(msg.obj.toString());
txt_Send.setText(udpSendStrBuf.toString());
break;
case 3:
txt_Recv.setText(udpRcvStrBuf.toString());
break;
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
bindWidget(); //控制元件繫結
listening(); //監聽事件
bindReceiver();//註冊broadcastReceiver接收器
iniWidget(); //初始化控制元件狀態
}
private void bindWidget(){
txt_Recv = (TextView)findViewById(R.id.txt_Recv);
txt_Send = (TextView)findViewById(R.id.txt_Send);
btn_CleanRecv = (Button)findViewById(R.id.btn_CleanRecv);
btn_Send = (Button)findViewById(R.id.btn_Send);
btn_UdpConn = (Button)findViewById(R.id.btn_udpConn);
btn_UdpClose = (Button)findViewById(R.id.btn_udpClose);
edit_Send = (EditText)findViewById(R.id.edit_Send);
}
private void listening(){
btn_Send.setOnClickListener(myBtnClick);
btn_UdpConn.setOnClickListener(myBtnClick);
btn_UdpClose.setOnClickListener(myBtnClick);
btn_CleanRecv.setOnClickListener(myBtnClick);
}
private void bindReceiver(){
IntentFilter udpRcvIntentFilter = new IntentFilter("udpRcvMsg");
registerReceiver(broadcastReceiver,udpRcvIntentFilter);
}
private void iniWidget(){
btn_Send.setEnabled(false);
}
class MyBtnClick implements Button.OnClickListener{
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_CleanRecv:
udpRcvStrBuf.delete(0,udpRcvStrBuf.length());
Message message = new Message();
message.what = 3;
myHandler.sendMessage(message);
break;
case R.id.btn_udpConn:
//建立執行緒池
ExecutorService exec = Executors.newCachedThreadPool();
client = new UDPClient();
exec.execute(client);
btn_UdpClose.setEnabled(true);
btn_UdpConn.setEnabled(false);
btn_Send.setEnabled(true);
break;
case R.id.btn_udpClose:
client.setUdpLife(false);
btn_UdpConn.setEnabled(true);
btn_UdpClose.setEnabled(false);
btn_Send.setEnabled(false);
break;
case R.id.btn_Send:
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = 2;
if (edit_Send.getText().toString()!=""){
client.send(edit_Send.getText().toString());
message.obj = edit_Send.getText().toString();
myHandler.sendMessage(message);
}
}
});
thread.start();
break;
}
}
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra("udpRcvMsg")) {
Message message = new Message();
message.obj = intent.getStringExtra("udpRcvMsg");
message.what = 1;
Log.i("主介面Broadcast","收到"+message.obj.toString());
myHandler.sendMessage(message);
}
}
};
}
當然,不能忘記在AndroidMainFest檔案中加上許可權,畢竟你是要聯網的!<uses-permission android:name="android.permission.INTERNET" />
寫在最後:實現這些功能其實較為簡單,網上有很多成熟且很棒的例子,各位多看多學,必沒有問題!其中進位制轉換其實很簡單實現,各位只要對那兩個stringbuffer進行進位制操作和顯示即可!
通訊效果請點選上方UDP server最後有圖片展示
附上demo:
http://download.csdn.net/detail/shankezh/9442049