怎样实现UDP通信,使Android设备上的数据成功发送到PC机上?

先创建两个项目:

Android设备项目为:Android Application Project,项目名:UDPSend

PC机的项目为:Java Project,项目名:UDPreceiver

为Android项目添加组件:Button 1个、 EditText 1个,如图所示

怎样实现UDP通信,使Android设备上的数据成功发送到PC机上?_第1张图片

·问题解决标志:当按下Button组件时,EditText组件上输入的内容将被传送到PC机上,并显示出来。

 

着手问题前,先了解如下概念:

①、UDP协议发送和接受数据用到类DatagramSocket:

Java使用DatagramSocket代表UDP协议的Socket,DatagramSocket本身只是码头,不维护状态,不能产生IO流,它的唯一作用就是接收和发送数据报,Java使用DatagramPacket来代表数据报,DatagramSocket接收和发送的数据都是通过DatagramPacket对象完成的。

类DatagramSocket有3个构造方法:

DatagramSocket():创建一个DatagramSocket实例,并将该对象绑定到本机默认IP地址、本机所有可用端口中随机选择的某个端口。

DatagramSocket(int prot):创建一个DatagramSocket实例,并将该对象绑定到本机默认IP地址、指定端口。

DatagramSocket(int port, InetAddress laddr):创建一个DatagramSocket实例,并将该对象绑定到指定IP地址、指定端口。

通过上面三个构造器中的任意一个构造器即可创建一个DatagramSocket实例,通常在创建服务器时,创建指定端口的DatagramSocket实例--这样保证其他客户端可以将数据发送到该服务器。

一旦得到了DatagramSocket实例之后,就可以通过如下两个方法来接收和发送数据。

receive(DatagramPacket p):从该DatagramSocket中接收数据报。

send(DatagramPacket p):以该DatagramSocket对象向外发送数据报。

从以上的“发送”和“接受”方法中,我们可以感受到,DatagramSocket这个类就像一个快递员,但这个“快递员”只会用手接送快递,却不认“发件人”和“收件人”,因此它是“盲目”的。

 

接着上面的例子,我们分别用:

(1)、InetAddress类对象存放快递员“送货地址”。该类有一个重要的方法为:InetAddress.getByName("host");

其中方法中的“host”表示“送货地址”,即:pc机当前所连WLAN的IPV4地址。

输入"cmd"后,再在“命令提示符”里输入“ipconfig/all”后可以找到。

(2)、DatagramPacket类对象表示快递员运送的“包裹”,该类有两个重要的构造方法:

public DatagramPacket(byte[] data, int length)  :将以byte为单位,长度为length的数据data“打包”进一个DatagramPacket类对象中

public DatagramPacket(byte[] data,  int length, InetAddress host, int aPort):将以byte为单位,长度为length的数据data“打包”进一个DatagramPacket类对象中,并将其送入端口为aPort,地址为host的地点。

 

步骤一:要解决这个问题,先要给这两个项目搭建“桥梁”:

(1)、在服务端(发送端),为UDPSend项目中的SendActivity类创建方法void SendMsg(String msg)与对象DatagramSocket Socket;,代码如下:

DatagramSocket Socket;

private void SendMsg(String msg){
    	
    	Log.v("fasong", "开始发送!");
    	try {
    		if(Socket==null)
    			Socket = new DatagramSocket(5555);

			InetAddress serverAddress = InetAddress.getByName("192.168.31.9");
			byte data[] = msg.getBytes();//把要发送的数据转化为Byte形式
			DatagramPacket package1 = new DatagramPacket(data,data.length,
					serverAddress,6666);//设置一个发送包(相当于快递,写了快递的地址和编号)
			
			Socket.send(package1);//发送快递
			Log.v("fasong", "发送成功!");
			
		} catch (Exception e) {
			// 如果发送不成功,那么会在这里显示“发送异常”,并将异常类型打印出来。
			Log.v("fasong", "发送异常"+ e);
        
			e.printStackTrace();
		}//设置端口号,
    }

其中,我当前所连WLAN的IPv4地址为“192.168.31.9”,每个人应该视自己情况而定。

由于我在此只试着传送字符,所以发送数据前,我在这里先将数据存入一个byte数组中。然后将这个数组“打包”到一个DatagramPacket类的对象package1中,再进行发送。

 

(2)、在接受端(客户端),为UDPreceiver类设置“桥梁”代码如下:

public class UDPreceiver {

	/**
	 * @param args
	 */
	public static void main(String[] args)throws Exception {
		System.out.println("数据发送开始!");
		
		DatagramSocket socket = new DatagramSocket(6666); 
        //派遣一个快递员socket,让它来端口6666报道

		while(true){
		    byte[]  data=new byte[1024];
		    DatagramPacket pack = new DatagramPacket(data, 10);//“快递员socket”制作包裹
		    socket.receive(pack);    //"快递员socket"用以上制作的"包裹"pack接受数据

            
		    int len = pack.getLength();//获取接受到的数据报的长度值
		    byte[] tong = new byte[len];//借用以上长度值创造一个新的byte数组

		    for(int i = 0 ; i < len ; i++ )    //将原来数组里的信息复制到新数组中来
			    tong[i] = data[i];	//注意:这两个数组的长度不同,tong[len]的长度一般来说远            
                                    //    小于data[1024]
		
		String str=new String(tong);
		System.out.println("收到信息: "+str);
		 
	}
	}
}

 

值得注意的是:

①、第一段代码里的Socket与第二段代码里的socket在生成时最好设置成两个序号不同的端口号,以表示这两个端口号独立,不会出现端口重复占用的问题。如上:发送端口为5555,接受端口为6666

②、在接受端,用“包裹”pack的长度构造一个新数组tong[],用来输出。是因为,如果直接用data[]输出,由于数组长度为1024,太长,因而会在输出接收到的数据后,同时输出大量冗余的“空”信息。这样做是为了保持输出数据的准确性。

 

步骤二:在搭建好的“桥梁”上,落实发送的工作。

(1)、在服务端(发送端)UDPSend项目中,SendActivity类代码如下:

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_send);
        
        Button Bt = (Button)this.findViewById(R.id.bt1);
        final EditText et = (EditText)this.findViewById(R.id.eT1);
        //创建好界面图标,并与执行程序连接

        Bt.setOnClickListener(new OnClickListener(){


			//当按下按钮时,执行以下方法
			public void onClick(View v) {
				// TODO Auto-generated method stub
				new Thread(){
					
					public void run(){						
						String str = et.getText().toString();//获取输入框的信息
						Log.v("fasong","可以发送!发送数据为:"+ str);
						SendMsg(str);   //只要一按按钮,就发送数据
				}
				}.start();
			}	
        });    //这里是监听器构造完毕之处,这种构造监听器的方法被称为“匿名类”,是常用的构造工具
        
        
    }

    

(2)、在客户端(接收端)为UDPreceiver类代码如下(同“步骤一”一样):

public class UDPreceiver {

	/**
	 * @param args
	 */
	public static void main(String[] args)throws Exception {
		System.out.println("数据发送开始!");
		
		DatagramSocket socket = new DatagramSocket(6666); 
        //派遣一个快递员socket,让它来端口6666报道

		while(true){
		    byte[]  data=new byte[1024];
		    DatagramPacket pack = new DatagramPacket(data, 10);//“快递员socket”制作包裹
		    socket.receive(pack);    //"快递员socket"用以上制作的"包裹"pack接受数据

            
		    int len = pack.getLength();//获取接受到的数据报的长度值
		    byte[] tong = new byte[len];//借用以上长度值创造一个新的byte数组

		    for(int i = 0 ; i < len ; i++ )    //将原来数组里的信息复制到新数组中来
			    tong[i] = data[i];	//注意:这两个数组的长度不同,tong[len]的长度一般来说远            
                                    //    小于data[1024]
		
		String str=new String(tong);
		System.out.println("收到信息: "+str);
		 
	}
	}
}

 

通过以上代码,达到效果:当按下按钮时,输入框上的数据会被发送到PC端

值得注意的是:

①、在发送端,监听器的Click()方法里,必须通过建立线程,在线程中实现传送数据的操作。这是因为,访问网络的操作不能主线程上进行,否则会出现异常android.os.NetworkOnMainThreadException(顾名思义)。

 

以上即为代码操作:

测试:

运行后,分别在android移动端的输入框里输入“555”,“1234567890”,“abcdefghijklmnopqrstuvwxyz”,得到结果如下:

怎样实现UDP通信,使Android设备上的数据成功发送到PC机上?_第2张图片

 

注意:容易出现的错误有:

①、java.net.SocketException: socket failed: EACCES (Permission denied)

出现这种异常,是大多因为接受端和发送端的权限没有设置好,这时候要检查发送端的AndroidManifest.xml:

怎样实现UDP通信,使Android设备上的数据成功发送到PC机上?_第3张图片

添加如上代码。

②、若出现java.net.BindException: bind failed:异常。

建议重启编程软件。

 

以上均为个人浅见。

你可能感兴趣的:(Android开发)