zoukankan      html  css  js  c++  java
  • 19.3 UDP程序设计基础

    1、概述
      基于UDP的信息传递更快,但不提供可靠的保证。使用UDP传递数据时,用户无法知道数据能否正确到达主机,也不能确定到达目的地的顺序是否和发送的顺序相同。虽然UDP是一种不可靠的协议,但如果需要较快地传输信息,并且能容忍小的错误,可以考虑使用UDP。
      基于UDP的基本模式如下:
        将数据打包(称为数据包),然后将数据包发往目的地
        接收别人发来的数据包,然后查看数据包。
      UDP程序的通讯步骤:
        发送数据包:
          (1)、使用DatagramSocket()创建一个数据包套接字。
          (2)、使用DatagramPacket(byte[] buf, int offset, in length, InetAddress address, int port)创建要发送的数据包。
          (3)、使用DatagramSocket类的send()方法发送数据包。
        接收数据包:
          (1)、使用DatagramSocket(int port)创建数据包套接字,绑定到指定的端口。
          (2)、使用DatagramPacket(byte[] buf, int length)创建字节数组来接收数据包。
          (3)、使用DatagramPacket类的receive()方法接收UDP包。
      注意:DatagramSocket类的receive()方法接收数据时,如果还没有困意接收的数据,在正常情况下receive()方法将阻塞,一致等到网络上有数据传来,receive()方法接收该数据并返回。如果网络上没有数据发送过来,receive()方法也没阻塞,肯定是程序有问题,大多数是使用了一个被其他程序占用的端口号。
    2、DatagramPacket类
      java.net包的DatagramPacket类用来表示数据包。DatagramPacket类的构造函数有:
        DatagramPacket(byte[] buf, int length)
        DatagramPacket(byte[] buf, InetAddress address, int port)
      第一种构造函数创建了DatagramPacket对象,指定了数据包的内存克难攻坚和大小。第二种构造函数不仅指定了数据包的内存空间和大小,还指定了数据包的目标地址和端口。在发送数据时,必须指定接收方的Socket地址和端口号,因此使用第二种构造函数可创建发送数据的DatagramPacket对象。
    3、DatagramSocket类
      java.net包中的DatagramSocket类用于表示发送和接收数据包的套接字。该类的构造函数如下:
        DatagramSocket()
        DatagramSocket(int port)
        DatagramSocket(int port, InetAddress addr)
      第一种构造函数创建DatagramSocket对象,构造数据报套接字并将其绑定到本地主机上任何可用的端口。第二种构造函数创建DatagramSocket对象,创建数据报套接字并将其绑定到本地主机上指定端口。第三中构造函数创建DatagramSocket对象,创建数据报套接字并将其绑定到指定的本地地址。第三种构造函数适用于有多块网卡和多个IP地址的情况。
      在接收程序时,必须指定一个端口号,不要让系统随机产生,此时可以使用第二种构造函数。比如有个朋友要你给他写信,可他的地址不确定是不行的。在发送程序时,通常使用第一种构造函数,不指定端口号,这样系统就会为我们分配一个端口号。就像寄信不需要到指定的邮局去寄一样。
    4、相关例子

     1 package com.lzw;
     2 
     3 import java.net.*;
     4 
     5 public class Weather extends Thread { // 创建类。该类为多线程执行程序
     6     String weather = "节目预报:八点有大型晚会,请收听";
     7     int port = 9898; // 定义端口
     8     InetAddress iaddress = null; // 创建InetAddress对象
     9     MulticastSocket socket = null; // 声明多点广播套接字
    10     
    11     Weather() { // 构造方法
    12         try {
    13             // 实例化InetAddress,指定地址
    14             iaddress = InetAddress.getByName("224.255.10.0");
    15             socket = new MulticastSocket(port); // 实例化多点广播套接字
    16             socket.setTimeToLive(1); // 指定发送范围是本地网络
    17             socket.joinGroup(iaddress); // 加入广播组
    18         } catch (Exception e) {
    19             e.printStackTrace(); // 输出异常信息
    20         }
    21     }
    22     
    23     public void run() { // run()方法
    24         while (true) {
    25             DatagramPacket packet = null; // 声明DatagramPacket对象
    26             byte data[] = weather.getBytes(); // 声明字节数组
    27             // 将数据打包
    28             packet = new DatagramPacket(data, data.length, iaddress, port);
    29             System.out.println(new String(data)); // 将广播信息输出
    30             try {
    31                 socket.send(packet); // 发送数据
    32                 sleep(3000); // 线程休眠
    33             } catch (Exception e) {
    34                 e.printStackTrace(); // 输出异常信息
    35             }
    36         }
    37     }
    38     
    39     public static void main(String[] args) { // 主方法
    40         Weather w = new Weather(); // 创建本类对象
    41         w.start(); // 启动线程
    42     }
    43 }
    View Code

     1 package com.lzw;
     2 
     3 import java.awt.*;
     4 import java.awt.event.*;
     5 import java.net.*;
     6 
     7 import javax.swing.*;
     8 
     9 public class Receive extends JFrame implements Runnable, ActionListener {
    10     /**
    11      * 
    12      */
    13     private static final long serialVersionUID = 1L;
    14     int port; // 定义int型变量
    15     InetAddress group = null; // 声明InetAddress对象
    16     MulticastSocket socket = null; // 创建多点广播套接字对象
    17     JButton ince = new JButton("开始接收"); // 创建按钮对象
    18     JButton stop = new JButton("停止接收");
    19     JTextArea inceAr = new JTextArea(10, 10); // 显示接收广播的文本域
    20     JTextArea inced = new JTextArea(10, 10);
    21     Thread thread; // 创建Thread对象
    22     boolean b = false; // 创建boolean型变量
    23     
    24     public Receive() { // 构造方法
    25         super("广播数据报"); // 调用父类方法
    26         setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    27         thread = new Thread(this);
    28         ince.addActionListener(this); // 绑定按钮ince的单击事件
    29         stop.addActionListener(this); // 绑定按钮stop的单击事件
    30         inceAr.setForeground(Color.blue); // 指定文本域中文字颜色
    31         JPanel north = new JPanel(); // 创建Jpane对象
    32         north.add(ince); // 将按钮添加到面板north上
    33         north.add(stop);
    34         add(north, BorderLayout.NORTH); // 将north放置在窗体的上部
    35         JPanel center = new JPanel(); // 创建面板对象center
    36         center.setLayout(new GridLayout(1, 2)); // 设置面板布局
    37         center.add(inceAr); // 将文本域添加到面板上
    38 
    39         final JScrollPane scrollPane = new JScrollPane();
    40         center.add(scrollPane);
    41         scrollPane.setViewportView(inced);
    42         add(center, BorderLayout.CENTER); // 设置面板布局
    43         validate(); // 刷新
    44         port = 9898; // 设置端口号
    45         try {
    46             group = InetAddress.getByName("224.255.10.0"); // 指定接收地址
    47             socket = new MulticastSocket(port); // 绑定多点广播套接字
    48             socket.joinGroup(group); // 加入广播组
    49         } catch (Exception e) {
    50             e.printStackTrace(); // 输出异常信息
    51         }
    52         setBounds(100, 50, 360, 380); // 设置布局
    53         setVisible(true); // 将窗体设置为显示状态
    54     }
    55     
    56     public void run() { // run()方法
    57         while (true) {
    58             byte data[] = new byte[1024]; // 创建byte数组
    59             DatagramPacket packet = null; // 创建DatagramPacket对象
    60             // 待接收的数据包
    61             packet = new DatagramPacket(data, data.length, group, port);
    62             try {
    63                 socket.receive(packet); // 接收数据包
    64                 String message = new String(packet.getData(), 0, packet
    65                         .getLength()); // 获取数据包中内容
    66                 // 将接收内容显示在文本域中
    67                 inceAr.setText("正在接收的内容:
    " + message);
    68                 inced.append(message + "
    "); // 每条信息为一行
    69             } catch (Exception e) {
    70                 e.printStackTrace(); // 输出异常信息
    71             }
    72             if (b == true) { // 当变量等于true时,退出循环
    73                 break;
    74             }
    75         }
    76     }
    77     
    78     public void actionPerformed(ActionEvent e) { // 单击事件
    79         if (e.getSource() == ince) { // 单击按钮ince触发的事件
    80             ince.setBackground(Color.red); // 设置按钮颜色
    81             stop.setBackground(Color.yellow);
    82             if (!(thread.isAlive())) { // 如线程不处于“新建状态”
    83                 thread = new Thread(this); // 实例化Thread对象
    84             }
    85             thread.start(); // 启动线程
    86             b = false; // 设置变量值
    87         }
    88         if (e.getSource() == stop) { // 单击按钮stop触发的事件
    89             ince.setBackground(Color.yellow); // 设置按钮颜色
    90             stop.setBackground(Color.red);
    91             b = true; // 设置变量值s
    92         }
    93     }
    94     
    95     public static void main(String[] args) { // 主方法
    96         Receive rec = new Receive(); // 创建本类对象
    97         rec.setSize(460, 200); // 设置窗体大小
    98     }
    99 }
    View Code

      注意:要广播或接受广播的主机地址必须加入到一个组内,地址范围为244.0.0.0~244.255.255.255,这类地址并不代表某个特定主机的位置。加入到同一个组的主机可以在某个端口上广播信息,也可以在某个端口上接收信息。

  • 相关阅读:
    php反射
    html video api控件总结
    linux CentOS7.2安装ffmpeg-3.0.2
    2019年7月12日星期五(C语言)
    2019年7月11日星期四(C语言)
    2019年7月10日星期三(C语言)
    2019年7月9日星期二(C语言)
    2019年7月8日星期一(C语言)
    2019年7月5日星期五(C语言)
    2019年7月4日星期四(C语言及LINUX命令)
  • 原文地址:https://www.cnblogs.com/studycode/p/9588523.html
Copyright © 2011-2022 走看看