欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android与PC之间的UDP通信

程序员文章站 2022-06-29 23:54:48
...
由于这段时间学习了安卓手机端与PC端之间的UDP通信原理,所以就在这里写一写自己的一些心得,我会尽量把自己遇到的难题以及自己的一些感觉写清楚,如果有写的不明朗的地方,还希望多多交流。	
在铺上代码之前,我觉得很有将UDP通信的一些函数解释清楚,这样便于读者对之后代码的理解!
UDP和TCP/IP协议一样都是痛通信协议。下面我将简单介绍一下UDP和TCP/IP之间的异同点。
TCP(Transmission Control  Protocol,传输控制协议)是面向连接的协议,也就是说在收发数据之间,双方必须建立可靠的连接,也就是行内术语“三次握手,四次挥手”这里就不作细述,网上有很多资料可查,读者有兴趣的话可以自己去看看。
UDP(User Data Protocol)UDP是一个非连接协议,传输数据之前,源端和终端之间是不建立连接的,简单的抓取来自应用程序的数据,并且将其扔到网络之上。
下面介绍实现安卓与PC之间通信需要的类,并对这些类的作用进行比较详细的叙述
DatagramSocket类:此类表示发送和接送数据的套接字(不明白可以直接跳过)
**简单解释一下DatagramSocket类的构造函数**
	DatagramSocket()//构造数据报套接字并将其绑定到本地主机上任何可用的端口
	Protected DatagramSocket (DatagramSocketImpl imp1)//创建带有指定DatagramSocketImpl的未绑定的数据报套接字
	DatagramSocket(int port)  //创建数据报套接字并将其绑定到本地主机绑定的端口号上
	DatagramSocket(int port, InetAddress laddr)//创建数据报套接字并将其绑定到本地指定的IP地址和端口号
	DatagramSocket(SocketAddress bindaddr) //创建数据报套接字,并将其绑定到本地指定的套接字地址
	
	**DatagramPacket类的构造函数**
	DatagramPacket(byte[] buf, int length) //构造DatagramPacket,并接收长度为length的数据包
	DatagramPacket(byte[] buf, int lenght, InetAddress address int port)  //将长度为length的数据包发送到主机上指定端口号
	DatagramSocket(byte[] buf, int offset, int lenght, InetAddress address int port)  //  构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号
   DatagramPacket(byte[] buf, int offset, int length)   //构造 DatagramPacket,用来接收长度为 length 的包,在缓冲区中指定了偏移量 
   DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)   //构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号
   DatagramPacket(byte[] buf, int length, SocketAddress address)   //构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号
         
**安卓端的源码**
public class MainActivity extends Activity {
	***DatagramSocket socket;***   **//在收发信息的过程中只需要创建一个DatagramSocket对象即可**

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		try {
			socket = new DatagramSocket(9999);
		} catch (SocketException e1) {

			e1.printStackTrace();
		}
		Button btn = (Button) this.findViewById(R.id.sendBtn);
		final EditText et = (EditText) this.findViewById(R.id.sendtext); // 为什么要添加final修饰
		TextView tv = (TextView) this.findViewById(R.id.receivetext); // 获取文本框的内容
		***// 发送信息的函数***
		btn.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				*new Thread(new Runnable() {
					public void run() {*   **//这里要说明一下在Android通信协议必须要放在线程里面进行**
						String str = et.getText().toString();
						Log.v("发送", str);
						***sendMsg(str);***  //sendMsg函数已经封装好,这里直接拿来用
					}
				}).start();
			}
		});

		**// 接收信息的函数**
		try {
			**receiveMsg();  //receiveMsg()函数也已经封装好,这里只需要拿来用即可,要体现java的封装思想**
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 定义发送消息的函数sendMsg()
	 */
	**public void sendMsg(String msg)** {
		Log.v("v", "开始发送");
		try {
			**socket = new DatagramSocket(9999); //用DatagramSocket创建一个sokcet对象发送数据包,9999是本机的端口号
			InetAddress server = InetAddress.getByName("192.168.31.207"); 
			 //上面代码的意思是获取本地主机的IP的地址,一般情况下使用InetAddress.getByName("IP")的形式,但是也可以用 getAllName()或者getLocalHost()的形式,得到本地主机的地址
			byte data[] = msg.getBytes();  //将字符串转换成字节流,因为底层的传输都是字节传输
			DatagramPacket pack = new DatagramPacket(data, data.length, server,
					6024); // 创建DatagramPacket 对象数据包,这里的6024是我们要发送信息主机的端口号
			socket.send(pack);**
			Log.v("f", "发送成功!");
		} catch (Exception e) {
			Log.v("f", "发送失败!");
			e.printStackTrace();
		}
	}

	**public void receiveMsg() throws Exception** {
		**// 创建线程,同理,接收信息也要放在线程里面接收**
		new Thread(new Runnable() {
			public void run() {
				if (socket != null) {
					try {
						String str;
						while (true) {
							**// 创建一个空的字节数组
							byte[] data = new byte[1024];
							// 将字节数组和数组的长度传进DatagramPacket 创建的对象里面
							DatagramPacket pack2 = new DatagramPacket(data,
									data.length);**
							Log.v("s", "pack2");
							Log.v("s", "开始接收");
							**socket.receive(pack2);  // socket对象接收pack包,程序启动的时候,socket会一直处于阻塞状态,直到有信息传输进来**
							String ip = pack2.getAddress().getHostAddress();  //这段代码的作用获取发送数据的IP地址
							int port = pack2.getPort();  //获取发送数据端的端口号
							System.out.println(ip);
							System.out.println(port);
							str = new String(pack2.getData(), 0, pack2.getLength()); // 将字节数组转化成字符串表现出来
							Log.v("s", "接收成功: " + str);
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}).start();

	}
	@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;
	}

}

PC端代码

**public class UDPServe**r{ 
	private SendandRecieveMsg srm; 
	public void UDPsetFrame(){
		srm = new SendandRecieveMsg();
		Frame frame = new Frame();
		frame.setTitle("QQ");  //设置标题名
		frame.setSize(800, 800);  //设置窗体的大小
		frame.setLayout(new FlowLayout());  //设置流式布局方式
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);  //设置可见
		TextField tf = new TextField(20);  //创建文本框, 20是指定的列数
		Button senBtn = new Button("发送");  //设置发送按钮
		TextArea ta = new TextArea(20,30);//创建文本域
		frame.add(tf);  //添加进frame窗体里面
		frame.add(senBtn); 

		frame.add(ta);  
		ActionLis ml = new ActionLis(tf,srm);  //将文本框里面内容传进去
		senBtn.addActionListener(ml);//给发送按钮加上监听器
		//关闭窗口调用的函数
		frame.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.exit(0);  //这个函数的意思就是把整个窗体停用下来
			}
		});
		while(true){
			try {
				**srm.UDPReceiveMsg(ta);   //接收信息的socket不断接收信息,而且必须要放在最后,不断while会阻断其他程序的进行,UDPReceiveMsg()函数已经封装进SendandRecieveMsg类中**
			} catch (SocketException e) {	
				e.printStackTrace();
			}
		}
	}
	public static void main(String[] arrys) throws IOException{
		new UDPServer().UDPsetFrame();  //主函数,创建对象并启动
	}

**public class ActionLis implements ActionListener**{
	private TextField tf;
	private SendandRecieveMsg srm;
	//构造函数
	public ActionLis() {
	}
	public ActionLis(TextField tf, SendandRecieveMsg srm) {  //构造函数将文本tf和srm传进来
		this.tf = tf;	
		this.srm = srm;
	}
	public void actionPerformed(ActionEvent e) {
		if(e.getActionCommand().equals("发送")){
			srm.UDPSendMsg(tf.getText().trim());   //发送信息个Android端
			System.out.println("发送的内容是:" + tf.getText().trim());
		}
	}
}


**public class SendandRecieveMsg**{
	DatagramSocket socket;  //定义DatagramSocket类对象
	public SendandRecieveMsg(){
		try {
			**socket = new DatagramSocket(6024);  //这里6024是我们PC的程序的端口号**
		} catch (SocketException e) {
			
			e.printStackTrace();
		}
	}
	/**
	 * 定义发送信息函数
	 */
	**public void UDPSendMsg(String msg)**{
    	if(socket != null) {
    		try {
				**InetAddress server = InetAddress.getByName("192.168.31.175");
	    		byte data[] = msg.getBytes();
	    		DatagramPacket pack = new DatagramPacket(data, data.length, server, 9999); //这是对方网络软件的端口
	    		socket.send(pack);  //这段代码在Android端已经介绍过,所以在这里就不再详述**
	    		System.out.println("发送成功");
			} catch (Exception e) {
				System.out.println("发送失败");
				e.printStackTrace();
			}  
    		
    	}
	}
	
	
	/**
	 * 定义接收信息函数
	 */
	**public void UDPReceiveMsg(TextArea ta) throws SocketException**{
		String str = null;
		while(true) {
			//创建字节数组
			byte[] data = new byte[100];
			//将字节数组和数组的长度传进DatagramPacket里面
			DatagramPacket pack1 = new DatagramPacket(data, data.length);
			try {
				System.out.println("启动");
				**//socket对象接收pack包
				socket.receive(pack1);
				String ip = pack1.getAddress().getHostAddress();  //获取IP地址
				int port = pack1.getPort();//这段代码在Android端已经介绍过,所以在这里就不再详述**
				str = new String(pack1.getData(), 0, pack1.getLength());  
				str = ip + ":" + port + ":" + str;
				ta.insert(str, pos);  //将消息插到文本里面
		    	if(str.equals("bye")){
					socket.close();  //关闭接口
				}
				} catch (Exception e) {
					System.out.println("发生异常");
					e.printStackTrace();
			  }  
		}
	}
}



有什么不对的地方,希望读者可以提出意见,其实只要把了解UDP通信的原理,再将UDP通信的几个函数的用于弄清楚,就会对通信的底层原理理解的更加深刻。

相关标签: 通信