《互联网程序设计(Java)》——课程笔记7:UDP套接字程序设计(无连接)
学会使用UDP套接字来实现网络应用程序设计。
UDP通信特点:
(1) UDP有别于TCP,有自己独立的套接字(IP+PORT),它们的端口号不冲突;
(2) UDP 通信前通常[不]需要连接;
(3) 基于用户数据报文(包)读写;
(4) UDP通信一般用于线路质量好的环境,如局域网内。
1. 程序设计第一步:创建UDPClient.java程序
UDPClient.java源程序见下面。
(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);//往报文中填充数据
2.程序设计第二步:创建UDPClientJFrame.java程序
用户界面如图1所示。
图1 UDP用户界面
(1) 在“连接”按钮中实例化UDPClient对象,并启动接收信息的“读线程”;
(2) 在“发送”按钮中设置发送信息的动作代码;
(3) 在“退出”按钮中设置退出程序运行代码。
3.程序设计第三步:创建UDPServer.java程序
根据UDPClient.java程序,创建对应的UDPServer服务器程序。服务器程序的功能是接收用户信息,并能自动返回用户信息。
完成UDPServer服务器程序后,启动你的服务器,首先能实现和自己的客户端成功对话。
部分代码:
UDPClient.java:
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(1***);
}
//定义一个数据的发送方法。
public void send(String msg){
try {
//先准备一个待发送的数据报
byte[] outputData=msg.getBytes("GB2312");
//构建一个数据报文。
DatagramPacket outputPacket=new DatagramPacket(outputData,
outputData.length,remoteIP,remotePort);
//给UDPServer发送数据报
socket.send(outputPacket); //给UDPServer发送数据报
} catch (IOException ex) { }
}
//定义一个数据的接收方法。
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();//释放本地端口.
}
}
连接按钮:
实例化UDPClient对象,并启动接收信息的“读线程”;
//连接按钮
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
ip = jTextField1.getText();
port = jTextField2.getText();
try
{
//实例化
client = new UDPClient(ip,port);
//同时实例化读线程
Thread receiver = new Thread()//用一个线程专门来接收信息
{
public void run()
{
String msg = null;
while((msg = client.receive())!=null)
{
jTextArea1.append(msg + "\n");
}
jTextArea1.append("对话框已关闭! \n");
}
};
receiver.start();//启动该线程
}catch(Exception e)
{
e.printStackTrace();
}
}
服务器:
ublic class UDPServer {
private final static int DEFAULT_PORT = 8800;
private final static int MAX_PACKET_SIZE = 512;
public static void main(String args[])
{
int port = DEFAULT_PORT;
byte[] buffer = new byte[MAX_PACKET_SIZE];
try
{
DatagramSocket server = new DatagramSocket(port);
DatagramPacket packet = new DatagramPacket(buffer,buffer.length);
System.out.println("UDP server 启动在8800端口");
while(true)
{
server.receive(packet);
String s = new String(packet.getData(),packet.getOffset(),packet.getLength(),"GB2312");
System.out.println(packet.getAddress() + " at port: " + packet.getPort() + "says: \n" + s);
//先准备一个待发送的数据报
// byte[] outputData = msg.getBytes("GB2312");
//构建一个数据报文
String studentId = "201";
String studentName = "";
s =" " + studentId + "-" + studentName + "-" + new Date().toString() +"-"+ s;
byte[] outputData = s.getBytes("GB2312");
DatagramPacket outputPacket = new DatagramPacket(outputData, outputData.length, packet.getAddress(), packet.getPort());
//给UDPServer发送数据报
server.send(outputPacket);//发送数据报
System.out.println("服务器已经发送了数据给计分服务器");
//设置以后需要接受的长度
packet.setLength(buffer.length);
}
}catch(Exception e)
{
e.printStackTrace();
}
}
}
先启动服务器,再启动客户端。