这个篇博客来介绍一下用UDP协议进行网络编程。
UDP协议是一种面向无连接的协议。简单来说,它是类似的一个邮局系统(或者可以用发短信的原理去理解)。有收件人和发件人,发件人可以直接发送邮件,不关心收件人是否可以收到。而收件人则当知道有邮件过来时去拿即可,也不需要告知发件人是否收到。在早期QQ视频聊天中就采用的是UDP协议。这种协议的延迟比较少,但是可能会出现丢失数据报的情况。这种特性比较适合那些要求实时性强而不需要保证正确性的应用程序,如视频电话会议系统。想要进一步了解UDP协议的话可以自行查找资料。
学习UDP协议的网络编程依然是通过一个实例来学习,这个实例可能涉及到一点多线程的技术,这个技术在以后的博客中会讲解到。示例程序的需求是实现一个简单的聊天程序。
首先介绍一下应用的几个重要的java.net包中的用于UDP传输的几个类。
InetAddress:用于表示互联网协议的IP地址。此类中有很多静态方法,可以直接使用。getByName(String host),个顶主机名去顶主机的ip地址,返回值的是InetAdress类型。
DatagramPacket:用于表示数据包。用来实现无连接的数据包的投递,根据包中所包含的信息从一台机器路由到另一台机器。期间可能会选择不同的路由器,也不能保证安发送顺序到达。示例中主要用到了它的两种构造方法:DatagramPacket(byte[] buf, int length),用来接收长度为length的数据报;DatagramPacket(byte[] buf, int length, InetAddress address, int port),用来将长度为length的数据包发送到指定主机的指定端口号上。
DatagramSocket:用于发送和接收数据包的套接字(Socket)。主要的方法有发送方法:sent(DatagramPacket p)。接收方法:receive(DatagramPacket p),这个是阻塞式的方法,即当没有收到数据时一直在这里等待,知道有数据来为止。
程序思路。对于发送端来说,首先要接收控制台的输入的数据并将其封装到数据包中,通过DatagramSocket的发送功能把包发送出去,发送端需要循环输入,并设定好退出的条件。对于接收端来说,通过DatagramSocket的接收功能接收到数据报,再用数据包类的功能解析出包中所含的信息。程序代码如下:
package lzl.udp.demo.chat; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; class Send implements Runnable { private DatagramSocket ds; private static final int SENDPORT = 8088; public Send(DatagramSocket ds) { this.ds = ds; } public void run() { try { //read the input data BufferedReader br = new BufferedReader( new InputStreamReader( System.in)); String readLine = null; //read input always, but break out of the loop when read "quit" while(null != (readLine = br.readLine())) { if("quit".equalsIgnoreCase(readLine)) break; byte[] buf = readLine.getBytes(); //encapsulated the data into a DatagramPacket DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("127.0.0.1"), SENDPORT); //send the packet ds.send(dp); } ds.close(); }catch(Exception e) { e.printStackTrace(); } } } class Receive implements Runnable { private DatagramSocket ds; private static final int SIZE = 1024; public Receive(DatagramSocket ds) { this.ds = ds; } public void run() { try { while(true) { byte[] buf = new byte[SIZE]; DatagramPacket dp = new DatagramPacket(buf, buf.length); //receive the packet ds.receive(dp); String dataIP = dp.getAddress().getHostAddress(); String data = new String(dp.getData(), 0, dp.getLength()); System.out.println(dataIP + " : " + data); } }catch(Exception e) { e.printStackTrace(); } } } public class UdpChatDemo { public static void main(String[] args) throws Exception { //private final int LISTENPORT = 8088; final int LISTENPORT = 8088; DatagramSocket sendSocket = new DatagramSocket(); DatagramSocket receiveSocket = new DatagramSocket(LISTENPORT); new Thread(new Send(sendSocket)).start(); new Thread(new Receive(receiveSocket)).start(); } }
程序中main方法中注释掉了一行(第90行),这一行犯了一个比较低级的错误。错误提示是“illegal modifier for parameter ×××, only final is permitted”。public/private/protected是声明做用域的,放在类中时修饰方法或这一个域,而方法内部定义的变量只能在方法内部使用(做参数传出不算),在这里声明作用域无意义,也就禁止声明public/private/protected。所以说在方法内部声明变量只能在需要的时候用final修饰符修饰,除此之外不能用其它修饰符修饰,包括static都不能修饰变量。
这篇关于应用UDP协议进行网络编程的博客内容就讲这多,后面还有后续的一些关于网络编程的博客。
参考资料:
1. JDK1.7 API:http://docs.oracle.com/javase/7/docs/api/
2. Java编程思想(第四版)
3. Java核心技术 卷1/卷2
4. 传智播客毕向东Java基础视频教程
5. 错误提示的分析参考:http://blog.csdn.net/ccccdddxxx/article/details/8051201
说明:
如有错误还请各位指正,欢迎大家一起讨论给出指导。
上述程序完整代码的下载链接:
https://github.com/zeliliu/BlogPrograms/tree/master/Java%E5%AD%A6%E4%B9%A0/udp_chat_demo
最后更新时间:2013-04-19