《網際網路程式設計(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();
}
}
}
先啟動伺服器,再啟動客戶端。