《互联网程序设计(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所示。

《互联网程序设计(Java)》——课程笔记7:UDP套接字程序设计(无连接)

 

图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();
        }
    }
}

先启动服务器,再启动客户端。