完成日期:2018.10.31
GitHub:https://github.com/fyinh/network_programming_course/tree/master/ch06
教学与实践目的:学会使用UDP套接字来实现网络应用程序设计。
UDP通信特点:
(1) UDP有别于TCP,有自己独立的套接字(IP+PORT),它们的端口号不冲突;
(2) UDP 通信前通常[不]需要连接;
(3) 基于用户数据报文(包)读写;
(4) UDP通信一般用于线路质量好的环境,如局域网内。
几个关键的Java类:DatagramSocket,DatagramPacket,MulticastSocket。
UDPClient.java源程序见附录1。
(1)UDP套接字类: DatagramSocket
不像TCP通信有客户套接字Socket和服务器套接字ServerSocket两种,而UDP套接字只有一种DatagramSocket,不区分客户套接字和服务器套接字。
UDP套接字的两个重要方法是:
发送网络数据用:
DatagramSocket.send(packet); //发送一个数据包
接收网络数据用:
DatagramSocket.receiver(packet);//接收一个数据包`
其中packet属于 DatagramPacket报文类的一个实例对象,用户数据封装在packet中。
(2)UDP数据报文类:DatagramPacket。
TCP发送数据是基于字节流的,而UDP发送数据是基于报文DatagramPacket,网络中传递的UDP数据都要封装在报文中。
报文类的两个重要方法是:
Byte[] b=DatagramPacket.getData();//从报文中取数据
DatagramPacket.setData(String msg);//往报文中填充数据
用户界面如下图所示。
演示过程:
(1)在“连接”按钮中实例化UDPClient对象,并启动接收信息的“读线程”;
(2)在“发送”按钮中设置发送信息的动作代码;
(3)在“退出”按钮中设置退出程序运行代码。
(4)验证和服务器通话。
根据UDPClient.java程序,创建对应的UDPServer服务器程序。服务器程序的功能是接收用户信息,并能自动返回用户信息。
组播是指在一群用户范围内发送和接收信息,该信息具有共享性。UDP具有组播功能,而TCP不具有。
组播地址的格式为:224...*,比如:224.1.10.10。组播地址号唯一标示一群用户(一定网络范围内,仅限于局域网络内或有些自治系统内支持组播)。
组播套接字类:MulticastSocket及其几个重要的方法:
(1)路由器、交换机一般只转发和终端机一致IP地址和广播地址数据,终端机如何知道要接收组内信息?要先声明加入或退出某一组播组,其方法是:
MulticastSocket ms=new MulticastSocket(8900);
ms.joinGroup(groupIP);//加入groupIP组
//作用:告知自己的网络层该IP地址的包要收;
//转告上联的路由器这样的IP地址包要转发。
ms.leaveGroup(groupIP);//退出groupIP组
(2)组内接收和发送信息的方法同UDP单播,其方法是:
ms.send(packet);
ms.receiver(packet).
(3)独立完成组播程序MulticastQQ.java和MulticastQQJFrame.java,组播套接字为:[224.0.1.8:8900],在组内发言要求以“201********* 姓名*”为信息头。其效果如下图所示,要求每位同学都能看到组内其他同学的留言。
要求支持用户验证、在线提示、单人及群组聊天等。
附录:
一、 UDP客户端程序
public class UDPClient {
private int remotePort;
private InetAddress remoteIP;
private DatagramSocket socket; //UDP套接字
public UDPClient(String ip, String port) throws IOException{
this.remotePort=Integer.parseInt(port);
this.remoteIP=InetAddress.getByName(ip);
//创建一个UDP套接字,与本地任意一个未使用的UDP端口绑定
socket=new DatagramSocket();
//与本地一个固定的UDP端口绑定
//socket=new DatagramSocket(9000);
}
//定义一个数据的发送方法。
public void send(String msg){
try {
byte[] outputData = msg.getBytes("GB2312");
//构建一个数据报文。
DatagramPacket outputPacket;
outputPacket = new DatagramPacket(outputData,outputData.length,remoteIP,remotePort);
socket.send(outputPacket); //给UDPServer发送数据报
} catch (IOException ex) {
ex.printStackTrace();
}
}
//定义一个数据的接收方法。
public String receive(){//throws IOException{
String msg;
//先准备一个空数据报文
DatagramPacket inputPacket = new DatagramPacket(new byte[512],512);
try{
//阻塞语句,有数据就装包,以装完或装满为此.
socket.receive(inputPacket);
//从报文中取出字节数据并装饰成字符。
msg = new String(inputPacket.getData(),0,inputPacket.getLength(),"GB2312");
}catch(IOException ex){
msg = null;
}
return msg;
}
public void close(){
if(socket != null){
socket.close();//释放本地接口
}
}
}
二、组播程序
public class MulticastQQ {
InetAddress groupIP;// = InetAddress.getByName("224.0.1.8");
int port = 8900;
MulticastSocket ms = null; //组播套接字
byte[] inBuff;
byte[] outBuff;
public MulticastQQ() throws IOException
{
groupIP = InetAddress.getByName("224.0.1.8");
ms = new MulticastSocket(port); //开启一个组播端口(UDP端口)
ms.joinGroup(groupIP); //告诉网卡这样的IP地址数据包要接收
inBuff = new byte[1024];
outBuff = new byte[1024];
}
public void send(String msg)
{
try
{
outBuff = ("20121000000老师 : " + msg).getBytes("GBK");
DatagramPacket outdp = new DatagramPacket(outBuff, outBuff.length, groupIP, port);
ms.send(outdp);
}catch(Exception e)
{
e.printStackTrace();
}
}
public String receive()
{
try
{
DatagramPacket indp = new DatagramPacket(inBuff,inBuff.length);
ms.receive(indp);
String msg = new String(indp.getData(), 0, indp.getLength(), "GBK");
return indp.getAddress() + "--->" + msg;
}catch(Exception e)
{
return null;
// e.printStackTrace();
}
}
public void close()
{
try
{
ms.leaveGroup(groupIP);
ms.close();
}catch(Exception e)
{
e.printStackTrace();
}
}
}