(28)网络编程之UDP
介绍UDP通信协议的编程之前,先介绍一下网络编程,socket相关的概念:
网络编程:网络编程主要用于解决计算机与计算机(手机平板等)之间的数据传输问题。
网络编程:不需要基于html网页就可以达到数据之间的传输。比如,飞秋,QQ,微信等等
网页编程:基于html页面的基础上进行数据的交互与传输。比如说淘宝,oa(办公自动化)等
计算机网络:分布在不同地域的计算机通过外部设备相互连接起来达到了消息互通,资源共享的效果,这就叫做计算机网络、
网络通讯的三要素:
1、IP,计算机在网络中唯一的身份标识
2、端口号:用于表明该消息是给那个应用程序处理的,只不过是一个标识符而已。
3、协议:一种规范,保障硬件间的良好兼容
IP地址:ip地址的本质就是一个有32位的二进制数组成的数据。
00000000-00000000-00000000-00000000 为了便于记忆,每8bit(1Byte)转换成一个十进制的数,0-255
IP地址是 由网络号+主机号 组成的。子网掩码位数,就是网络号的位数
IP地址的分类
A类地址:1个网络号 + 3个主机号 2^24 政府单位使用
B类地址:2个网络号 + 2个主机号 2^16 事业单位使用
C类地址:3个网络号 + 1个主机号 2^ 8 私人使用
Java中的IP类:InetAddress
常用的方法:
getLocalHost() 获取本机的ip地址 对象. ——静态方法
getByName("IP或者主机名")根据主机名或者一个ip地址的字符串形式,生成一个一片地址《对象》(获取别人的主机地址)
getHostAddress() 返回一个本机的ip地址字符串的形式
getHostName() 返回计算机的主机名
InetAddress.getAllByName("ip地址、主机名、域名") 返回一个InetAddress[]
InetAddress[] arr = InetAddress.getAllByName("www.baidu.com");
for (InetAddress inetAddress : arr)
{
System.out.println(inetAddress.getHostAddress());
}
上面的getAllByName("www.baidu.com")你可以发现输出的是两台主机,并不是一台主机有两个ip地址的问题。www.baidu.com是一个域名,这个域名需要有ISR供应商的dns服务器进行解析,一般百度之类的大公司,在ISR那注册的服务器都不知一个,白的就是上面两个,这两个服务器的作用主要就是为了实现转发的功能在这两个服务器的后面可能还有大批的服务器集群。
端口号:是没有用来描述的,端口号只相当于一个标识而已。
端口号的范围0-65535之间。
端口号不是对标指定的,有一下的分类:其中后两类基本上都能使用
公认端口(WellKnownPorts):从0到1023,它们紧密绑定(binding)于一些服务。
注册端口(RegisteredPorts):从1024到49151。它们松散地绑定于一些服务。
动态和/或私有端口(Dynamicand/orPrivatePorts):从49152到65535。
常用端口:
21 FTP
80 HTTP
443 HTTPS
网络通信的协议:
UDP通信协议
TCP通信协议
在Java中网络通讯也称之为Socket(套接字,插座)通信,要求通信的两端都要安装Socket。
不同的协议就有不同的插座(Socket)
UDP通信协议
的特点
1、将数据极其源和目的封装为数据包,面向无连接。
2、每个数据包大小限制在64K中
3、因为无连接,所以不可靠,有可能出现数据包丢失的情况
4、因为不需要建立连接,所以速度快
5、udp通信部分服务端与客户端,只分发送端与接收端
如:人说话、对讲机、飞秋、凌波、CS枪战游戏等
udp协议下的Socket:
DatagramSocket(udp插座服务):发送与接收都是用该类
DatagramPacket(数据包类)
DatagramPacket(buf, length, address, port)
buf发送的内容
length发送内容的大小
address发送的目的地ip地址对象
port是一个端口号
发送端的使用步骤:
1、建立udp的服务
2、准备数据,把数据封装到数据包中发送
3、发送端的数据包要带上一个ip地址与端口号。
3、调用udp的服务发送数据。
4、关闭资源
1 //发送端 完全模拟码头发货的过程 2 public class Demo1Sender 3 { 4 public static void main(String[] args) throws IOException 5 { 6 //建立udp的服务 7 DatagramSocket datagramSocket = new DatagramSocket();//直接使用午餐构造方法就行了 8 //准备数据,把数据封装到发送包中 9 String data = "这是一个udp的例子..."; 10 DatagramPacket datagramPacket = new DatagramPacket(data.getBytes(), data.getBytes().length, InetAddress.getLocalHost(), 9090); 11 //调用udp的服务发送数据包 12 datagramSocket.send(datagramPacket); 13 //关闭资源---实际上就是释放占用的端口号 14 datagramSocket.close(); 15 } 16 }
接收端的使用步骤
1、建立udp的服务。
2、准备空的数据包,接受数据。(只要制定一个字节数组)
3、调用udp的服务接受数据。
4、关闭资源。
1 //接收端 2 public class Demo1Recieve 3 { 4 public static void main(String[] args) throws IOException 5 { 6 //建立udp插座服务,监听一个端口 7 DatagramSocket datagramSocket = new DatagramSocket(9090); 8 //准备空的数据包用于存储数据 9 byte[] buf = new byte[1024]; 10 DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length); 11 //调用udp的服务接受数据 12 datagramSocket.receive(datagramPacket); //数据实际上存储到了 buf 字节数组中.recieve方法是一个阻塞方法,没有接收到数据就会一直处于阻塞状态。 13 14 System.out.println("接收端接受到的数据:"+new String(buf, 0, datagramPacket.getLength()));//getLength()获取数据包存储的字节,到底接受了多少字节,datagramPacket最清楚 15 16 //关闭资源 17 datagramSocket.close(); 18 } 19 }
很明显运行上面的示例程序的时候,应当先启动接收端的,接收端处于一种等待接收信息的阻塞状态。然后在运行发送端的,发送端运行,发出数据,接收端接受数据之后,程序接受。
群聊示例,关键是接收端发送端一定要使用多线程,发送端的消息数据包中的地址应
1 当是广播地址。 2 发送端: 3 public class ChatSender extends Thread 4 { 5 @Override 6 public void run() 7 { 8 //建立udp的服务 9 try 10 { 11 DatagramSocket socket = new DatagramSocket(); //发送端不需要地址 12 //准备数据,把数据封装到数据包中 13 BufferedReader keyReader = new BufferedReader(new InputStreamReader(System.in)); 14 String line = null; 15 DatagramPacket packet = null; 16 while((line = keyReader.readLine())!=null) 17 { 18 //把数据封装到数据包中,发送出去 19 packet = new DatagramPacket(line.getBytes(), line.getBytes().length, InetAddress.getByName("192.168.1.255"), 9090); 20 //把数据包发送出去 21 socket.send(packet); 22 } 23 //关闭资源 24 socket.close(); 25 } catch (SocketException e) 26 { 27 // TODO Auto-generated catch block 28 e.printStackTrace(); 29 } catch (UnknownHostException e) 30 { 31 // TODO Auto-generated catch block 32 e.printStackTrace(); 33 } catch (IOException e) 34 { 35 // TODO Auto-generated catch block 36 e.printStackTrace(); 37 } 38 } 39 } 40 接收端: 41 //群聊的接收端 42 public class ChatRecieve extends Thread 43 { 44 @Override 45 public void run() 46 { 47 try 48 { 49 //建立udp的服务,接收端要监听一个端口 50 DatagramSocket socket = new DatagramSocket(9090); 51 //准备一个空的集装箱 52 byte[] buf = new byte[1024]; 53 DatagramPacket packet = new DatagramPacket(buf, buf.length); 54 boolean flag = true; 55 while(flag) 56 { 57 socket.receive(packet); 58 //packet.getAddress()获取发送数据包的IP地址对象 59 System.out.println(packet.getAddress().getHostAddress()+"说:"+new String(buf, 0, packet.getLength())); 60 } 61 //关闭资源 62 socket.close(); 63 } catch (SocketException e) 64 { 65 // TODO Auto-generated catch block 66 e.printStackTrace(); 67 } catch (IOException e) 68 { 69 // TODO Auto-generated catch block 70 e.printStackTrace(); 71 } 72 } 73 } 74 //主程序 75 public class ChatMain 76 { 77 public static void main(String[] args) 78 { 79 ChatRecieve chatRecieve = new ChatRecieve(); 80 chatRecieve.start(); 81 82 ChatSender chatSender = new ChatSender(); 83 chatSender.start(); 84 } 85 } 86 启动主程序即可。