UDP协议中文名是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。与所熟知的TCP(传输控制协议)协议一样,UDP协议直接位于IP(网际协议)协议的顶层。根据OSI(开放系统互连)参考模型,UDP和TCP都属于传输层协议。UDP协议的主要作用是将网络数据流量压缩成数据包的形式。一个典型的数据包就是一个二进制数据的传输单位。每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。UDP数据包是面向无连接的,用户发出数据包不需要得到确认,因此是是不可靠的传输。

Android的UDP的数据传输和JAVA里没有什么区别。

UDP工具类:

package com.wifi.udp;
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.InetAddress;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.util.Log;


 /**
  * UDP工具类
  * @author Sunward
  *
  */
 public class UDPUtils implements Runnable {


public boolean keepRunning = true;//线程开始标志
public static final String TAG = "TEST";
//发送目的主机IP和端口
     private static String SERVER_IP;
     private static int SERVER_PORT;
     
     //本机监听的端口
     private static int LOCAL_PORT = 8929;
     
     //发送的消息
     private String message = "test";
     
     //服务器接收的消息
     private String receive;
     
     //Handler传递的数据
     private Message msg;
     //Message传递的Buddle参数
     private Bundle bundle;
     
     //wifi名和密码
     private String SSID,password;


     public UDPUtils(){

}


public UDPUtils(String Server_IP, int Server_Port) {
SERVER_IP = Server_IP;
SERVER_PORT = Server_Port;
}


public void setMessage(String message) {
this.message = message;
}
public String getMessage() {
return message;
}




/**
* 线程停止标志
* @param keepRunning
*/
public void setKeepRunning(boolean keepRunning) {
this.keepRunning = keepRunning;
}

public boolean getKeepRunning(){
return this.keepRunning;
}

  
/**
* 服务端监听程序
*/
public void StartListen()  {
keepRunning = getKeepRunning();
DatagramSocket socket = null;  
         byte[] data = new byte[1024];  
         DatagramPacket packet = new DatagramPacket(data, data.length);  
           
         try {  
             socket = new DatagramSocket(LOCAL_PORT);  
             socket.setBroadcast(true);
             Log.i(TAG, "socket");  
 //          socket.setSoTimeout(200);  
         } catch(Exception e) {  
             e.printStackTrace();  
             return;  
         }  
           
         while (keepRunning) {              
             try {  
                 //等待客户机连接  
                 packet.setData(data);  
                 Log.e(TAG, "receive0"); 
                 socket.receive(packet);  
                 receive = new String(packet.getData(), 0, packet.getLength());  
                 
                 msg = new Message();
                 bundle = new Bundle();
                 
                 //把数据放到buddle中
                 bundle.putString("receive", receive);
                 //把buddle传递到message
                 msg.setData(bundle);
                 myHandler.sendMessage(msg);
                 
             } catch (Exception e) {  
                 continue;  
             }  
         }  
           
         if (socket != null) {  
            socket.close();  
            socket = null;  
         }  
}
//利用Handler将接收的数据实时打印出来
Handler myHandler = new Handler(){
@Override
public void handleMessage(Message msg)
{ 
super.handleMessage(msg);
Bundle bundle=new Bundle();
//从传过来的message数据中取出传过来的绑定数据的bundle对象
bundle = msg.getData();
receive = bundle.getString("receive");
setMessage(receive);
} 
};

public void sendControInfo(String message){

try {  
             DatagramSocket sendSocket = new DatagramSocket();  
            
             byte[] configInfo = message.getBytes();
            
             InetAddress ip = InetAddress.getByName(SERVER_IP);  //即目的IP
             DatagramPacket sendPacket = new DatagramPacket(configInfo, configInfo.length, ip ,SERVER_PORT);// 创建发送类型的数据报:  
   
             sendSocket.send(sendPacket);    // 通过套接字发送数据:             
               
             sendSocket.close();  
         } catch (Exception e) {  
             e.printStackTrace();  
         }  
}

@Override
public void run() {
StartListen();
}
 }



MainActivity:

package com.wifi.main;


 import java.lang.Thread.State;
 import java.util.Map;
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.regex.Pattern;


 import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.TextView;
 import android.widget.Toast;


 import com.example.jushi_blub.R;
 import com.wifi.udp.UDPUtils;
 import com.wifi.utils.MyApplication;




 public class MainActivity extends Activity implements OnClickListener{
public static final String TAG = "MainActivity";  
     private Button send_udp,receive_udp,coapServer,coapClient;
     private long exitTime = 0;
     
     //发送或者接收的文本
     public static EditText send_msg,receive_msg;
     //目的主机IP
     private String SERVER_IP;
     private int SERVER_PORT;
     //本机监听端口
     private int LOCAL_PORT;
     
     private TextView infomation;
     
     private UDPUtils udpUtils;
     private String message;
     
     private Thread thread;
     
     private Map<String, Object> map;
     //用户输入的灯泡ID
     private int  bulbID;
     
     //用来存储全局变量,用于Activity之间的传递
     private MyApplication myApplication;
     //定时器,用来检测是否接收到成功消息
     private Timer timer;
     
     //灯泡的状态
     private String status = "off";
     
     /**
      * 初始化
      */
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
         
         initViews();
         myApplication = (MyApplication)this.getApplicationContext();
         map = myApplication.getMap();
         
         if (!map.isEmpty()) {
         SERVER_IP = map.get("IP").toString();
         SERVER_PORT = Integer.parseInt(map.get("Port").toString().trim());
         LOCAL_PORT = Integer.parseInt(map.get("LOCAL_PORT").toString().trim());
}else {

SERVER_IP = "192.168.0.107";
        SERVER_PORT = 9090;
        LOCAL_PORT = 8929;
}
         udpUtils = new UDPUtils(SERVER_IP,SERVER_PORT, LOCAL_PORT);
         infomation.append("目的IP: "+SERVER_IP+"\n"+"目的端口: "+SERVER_PORT+"\n");
         infomation.append("本地端口: " +LOCAL_PORT);
         
     }

     
     /**
      * 控件初始化
      */
     public void initViews(){
         send_udp = (Button) findViewById(R.id.send_udp);
         send_msg = (EditText) findViewById(R.id.message);
         receive_msg = (EditText) findViewById(R.id.receive);
         infomation =(TextView) findViewById(R.id.information);         send_udp.setOnClickListener(MainActivity.this);
     }
     
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         // Inflate the menu; this adds items to the action bar if it is present.
         getMenuInflater().inflate(R.menu.main, menu);
         return true;
     }


     /**  
      * 监听Back键按下事件,方法1:  
      * 注意:  
      * super.onBackPressed()会自动调用finish()方法,关闭  
      * 当前Activity.  
      */    
    /* @Override    
     public void onBackPressed() {    
         super.onBackPressed();    
     }    */
     
     
     @Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO 按两次返回键退出应用程序
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
// 判断间隔时间 大于2秒就退出应用
if ((System.currentTimeMillis() - exitTime) > 2000) {
// 应用名
String applicationName = getResources().getString(
R.string.app_name);
String msg = "再按一次返回键退出";
//String msg1 = "再按一次返回键回到桌面";
Toast.makeText(MainActivity.this, msg, 0).show();
// 计算两次返回键按下的时间差
exitTime = System.currentTimeMillis();
} else {
// 关闭应用程序
finish();
// 返回桌面操作
// Intent home = new Intent(Intent.ACTION_MAIN);
// home.addCategory(Intent.CATEGORY_HOME);
// startActivity(home);
}
return true;
}
return super.onKeyDown(keyCode, event);
}
     /**
      * 菜单单击事件
      */
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         // Handle action bar item clicks here. The action bar will
         // automatically handle clicks on the Home/Up button, so long
         // as you specify a parent activity in AndroidManifest.xml.
         int id = item.getItemId();
         if (id == R.id.wifi_config) {
         Intent intent = new Intent();
         intent.setClass(MainActivity.this, WIFIActivity.class);
         this.startActivity(intent);
             return true;
         }
         if (id == R.id.ip_config) {
         Intent intent = new Intent();
         intent.setClass(MainActivity.this, IPActivity.class);
         this.startActivity(intent);
             return true;
}
         return super.onOptionsItemSelected(item);
     }






     @Override
public void onClick(View view) {


switch (view.getId()) {  
        case R.id.send_udp:
       
                 new Thread(){
                 @Override
public void run(){
                 udpUtils.sendControInfo("Hello");
                 }
                 }.start();thread = new Thread(udpUtils);
thread.start();
       break;
        default:  
            break;  
         }  
}
     
     /**
      * 判断输入的是否为数字
      * @param str
      * @return
      */
     public static boolean isInteger(String str) {  
         Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");  
         return pattern.matcher(str).matches();  
   }

  

/**
* 判断开灯返回的数据
* @param receive
* @return
*/


@Override
     protected void onDestroy() {  
     super.onDestroy();
     //关闭线程
         udpUtils.setKeepRunning(false); 
     }  

 }


效果图:

android udp通信 文字 乱码 手机发送udp数据包_android udp通信 文字 乱码

android udp通信 文字 乱码 手机发送udp数据包_ide_02

在同一个局域网下进行测试,目的主机是电脑IP地址是192.168.0.107,安装了TCP/UDPb捕获软件,手机发送开关信号电脑的软件能够接收到,并且电脑发送消息手机也能监听到。这里要注意:

1.手机的点击按钮事件中的发送数据一定要放在线程里运行,否则会报主线程不能处理网络请求的相关异常。

2.监听接收数据时,也要启动一个线程,在UDPUtils中监听数据的端口号不能和发送的端口号相同,且接收数据需要放到Handler中处理,否则不能实时将数据打印在手机上。