Android之UDP協議通訊
阿新 • • 發佈:2018-11-26
最近在做的專案中用到了UDP協議來通訊,整理了一下,可以與PC端網路助手之間進行測試。下面將主要功能程式碼寫在下面供搭建參考:
UDPSocketClientManage
public class UDPSocketClientManage {
// 伺服器IP
private static String SERVER_IP = "192.168.1.68";
// 伺服器埠
private static int LOCAL_PORT_AUDIO = 10000;
// 接收資料包
private DatagramPacket Packet_Receive;
// 埠
private DatagramSocket msocketClient;
NetworkState mLastNetworkState = NetworkState.NETWORK_STATE_NULL;
SocketConnectListener mConnectListener = null;
// 設定網路連線引數
public void setNetworkParameter(String strIP, int nPort) {
SERVER_IP = strIP;
LOCAL_PORT_AUDIO = nPort;
}
// 註冊接收連線狀態和資料的回撥函式
public void RegSocketConnectListener(SocketConnectListener listener) {
mConnectListener = listener;
}
/**
* 啟動連線伺服器
*/
public void Connect() {
// 正在開始連線
mLastNetworkState = NetworkState.NETWORK_STATE_CONNECT_ING;
try {
// 埠
msocketClient = new DatagramSocket(LOCAL_PORT_AUDIO);
// 接收資料快取
byte[] Buffer_Receive = new byte[1024];
// 接收包
Packet_Receive = new DatagramPacket(Buffer_Receive, 1024);
mLastNetworkState = NetworkState.NETWORK_STATE_CONNECT_SUCCEED;
} catch (IOException e) {
mLastNetworkState = NetworkState.NETWORK_STATE_CONNECT_FAILLD;
Log.e("Show", e.toString());
e.printStackTrace();
} catch (Exception e) {
mLastNetworkState = NetworkState.NETWORK_STATE_CONNECT_FAILLD;
Log.e("Show", e.toString());
e.printStackTrace();
}
// 向回調發資料
if (null != mConnectListener) {
mConnectListener.OnConnectStatusCallBack(mLastNetworkState);
}
if (msocketClient != null) {
new Thread(reRunnable).start();
}
}
Runnable reRunnable = new Runnable() {
@SuppressLint("NewApi")
@Override
public void run() {
while (true) {
try {
// 接收資料
if (Packet_Receive != null) {
msocketClient.receive(Packet_Receive);
// 判斷資料是否合法
InetSocketAddress address = (InetSocketAddress) Packet_Receive.getSocketAddress();
// 判斷是否是排程伺服器的ip
if (!address.getHostName().equals(SERVER_IP)) {
continue;
}
// 判斷是否是排程伺服器的埠
if (address.getPort() != LOCAL_PORT_AUDIO) {
continue;
}
int length = Packet_Receive.getLength();
if (length > 0)
mConnectListener.OnReceiverCallBack(length, Packet_Receive.getData());
}
} catch (IOException e) {
e.printStackTrace();
Log.e("Show", e.toString());
}
}
}
};
/**
* 斷開連線
*/
public void Close() {
if (msocketClient != null) {
msocketClient = null;
mLastNetworkState = NetworkState.NETWORK_STATE_DISCONNECT_SUCCEED;
mConnectListener.OnConnectStatusCallBack(mLastNetworkState);
}
}
/**
* @param data :需要傳送的資料
* @param len :資料位元組資料
* @brief 傳送資料
*/
public void send(byte[] data, int len) {
Thread_Send thread_send = new Thread_Send(data, len);
new Thread(thread_send).start();
}
/**
* @brief 傳送執行緒
*/
private class Thread_Send implements Runnable {
// 傳送資料快取
private byte[] Buffer_Send = new byte[1024];
// 傳送資料包
private DatagramPacket Packet_Send;
/**
* @param data :需要傳送的資料
* @param len :資料位元組資料
* @brief 建構函式
*/
public Thread_Send(byte[] data, int len) {
// 傳送包
Packet_Send = new DatagramPacket(Buffer_Send, 1024);
Packet_Send.setData(data);
Packet_Send.setLength(len);
}
@Override
public void run() {
try {
Packet_Send.setPort(LOCAL_PORT_AUDIO);
Packet_Send.setAddress(InetAddress.getByName(SERVER_IP));
if (msocketClient != null) {
msocketClient.send(Packet_Send);
mLastNetworkState = NetworkState.NETWORK_STATE_TXD;
mConnectListener.OnConnectStatusCallBack(mLastNetworkState);
} else {
mLastNetworkState = NetworkState.NETWORK_STATE_NULL;
mConnectListener.OnConnectStatusCallBack(mLastNetworkState);
}
} catch (UnknownHostException e) {
e.printStackTrace();
mLastNetworkState = NetworkState.NETWORK_STATE_NULL;
mConnectListener.OnConnectStatusCallBack(mLastNetworkState);
} catch (IOException e) {
e.printStackTrace();
mLastNetworkState = NetworkState.NETWORK_STATE_NULL;
mConnectListener.OnConnectStatusCallBack(mLastNetworkState);
}
}
}
// 獲取最後的網路狀態
public NetworkState getLastNetworkState() {
return mLastNetworkState;
}
@SuppressLint("LongLogTag")
public static String getLocalIpAddress() {
try {
for (Enumeration<NetworkInterface> en = NetworkInterface
.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf
.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress()
&& !inetAddress.isLinkLocalAddress()) {
return inetAddress.getHostAddress().toString();
}
}
這裡寫程式碼片
} catch (SocketException ex) {
Log.e("WifiPreference IpAddress", ex.toString());
}
return null;
}
}
介面SocketConnectListener
public abstract class SocketConnectListener {
// 網路狀態回撥
public abstract void OnConnectStatusCallBack(NetworkState networkState);
// 接收資料回撥
public abstract void OnReceiverCallBack(int nLength, byte[] data);
}
網路狀態列舉類NetworkState
//網路狀態列舉類
public enum NetworkState {
NETWORK_STATE_NULL, // 無狀態
NETWORK_STATE_CONNECT_SUCCEED, // 網路連線成功
NETWORK_STATE_DISCONNECT_SUCCEED, // 網路斷開成功(自身斷開)
NETWORK_STATE_SERVER_DISCONNECT, // 網路被伺服器斷開
NETWORK_STATE_CONNECT_FAILLD, // 連線伺服器失敗,IP/埠不正常
NETWORK_STATE_CONNECT_ING, // 正在連線過程中...
NETWORK_STATE_RXD, // 接收資料
NETWORK_STATE_TXD; // 傳送資料
}
主頁面連線使用類MainActivity
public class MainActivity extends ActionBarActivity implements View.OnClickListener {
public static UDPSocketClientManage socketClientManage = null;
// private String mstrDataString = "";
private byte[] mstrDataString;
private TextView textViewRecrive;
public static byte[] bytes1_up = {(byte) 0xfa,(byte)0x01,(byte)0x05,(byte)0x01};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button1).setOnClickListener(this);
findViewById(R.id.button2).setOnClickListener(this);
findViewById(R.id.button3).setOnClickListener(this);
TextView loTextView = (TextView) findViewById(R.id.textViewLoca);
//手機端的連線路由之後IP地址,網路除錯助手向目標主機發送的IP地址就是這裡獲取出來的
String strLoString = UDPSocketClientManage.getLocalIpAddress();
if (strLoString != null) {
loTextView.setText(strLoString);
}
textViewRecrive = (TextView) findViewById(R.id.textViewRecrive);
socketClientManage = new UDPSocketClientManage();
socketClientManage.RegSocketConnectListener(new SocketConnectListener() {
@Override
public void OnReceiverCallBack(int nLength, byte[] data) {
// mstrDataString = new String(data);
mstrDataString = data;
mHandler.sendEmptyMessage(1);
}
@Override
public void OnConnectStatusCallBack(NetworkState networkState) {
switch (networkState) {
case NETWORK_STATE_CONNECT_SUCCEED:
mHandler.sendEmptyMessage(0);
break;
default:
break;
}
}
});
}
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0: // 接受到訊息之後,對UI控制元件進行修改
Toast.makeText(MainActivity.this, "連線成功", Toast.LENGTH_SHORT).show();
break;
case 1: // 接受到訊息之後,對UI控制元件進行修改
// textViewRecrive.append(mstrDataString);
// textViewRecrive.setText(bytesToHexString(mstrDataString.getBytes()));
// Toast.makeText(MainActivity.this, mstrDataString, Toast.LENGTH_SHORT).show();
//下面是以16進位制方式來接收
String str1 = Integer.toHexString(mstrDataString [0]& 0xFF);
String str2 = Integer.toHexString(mstrDataString [1]& 0xFF);
String str3 = Integer.toHexString(mstrDataString [2]& 0xFF);
String str4 = Integer.toHexString(mstrDataString [3]& 0xFF);
if (str1.length() == 1) {
str1='0' + str1;
}
if (str2.length() == 1) {
str2='0' + str2;
}
if (str3.length() == 1) {
str3='0' + str3;
}
if (str4.length() == 1) {
str4='0' + str4;
}
textViewRecrive.setText(str1+" "+str2+" "+str3+" "+str4);
break;
default:
break;
}
}
};
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
new Thread(new Runnable() {
@Override
public void run() {
socketClientManage.Connect();
}
}).start();
break;
case R.id.button2:
EditText ipEditText = (EditText) findViewById(R.id.editText1);
EditText porText = (EditText) findViewById(R.id.editText2);
String ipString = ipEditText.getText().toString().trim();
String portString = porText.getText().toString().trim();
socketClientManage.setNetworkParameter(ipString, portString != null ? Integer.parseInt(portString) : 0);
Toast.makeText(MainActivity.this, "設定成功", Toast.LENGTH_SHORT).show();
break;
case R.id.button3:
socketClientManage.send(bytes1_up, bytes1_up.length);
break;
default:
break;
}
}
}
佈局.xml檔案
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="本地IP地址:" />
<TextView
android:id="@+id/textViewLoca"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<EditText
android:id="@+id/editText1"
android:layout_width="match_parent"
android:layout_height="40dp">
<requestFocus />
</EditText>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PC端的IP地址(也就是傳送資料伺服器地址):" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PC端的IP埠(也就是傳送資料伺服器埠):" />
<EditText
android:id="@+id/editText2"
android:layout_width="match_parent"
android:layout_height="40dp"
android:inputType="number" >
<requestFocus />
</EditText>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="傳送給PC端的資料" />
<EditText
android:id="@+id/editText3"
android:layout_width="match_parent"
android:layout_height="40dp" >
<requestFocus />
</EditText>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:text="確定" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:text="連線" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="傳送" />
</LinearLayout>
<TextView
android:id="@+id/textViewRecrive"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="接收到的資料:" />
</LinearLayout>
最後別忘了在AndroidManifest.xml裡新增許可權
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
以上這些就是全部程式碼,有不足指出還請大家指出
下面為大家附上原始碼