Java UDP Socket

来源:互联网 发布:linux系统可以玩lol吗 编辑:程序博客网 时间:2024/06/06 04:03

一. UDP协议定义

UDP协议的全称是用户数据报,在网络中它与TCP协议一样用于处理数据包。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据报分组、组装和不能对数据包的排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。

二. 使用UDP的原因
它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。比如我们聊天用的ICQ和OICQ就是使用的UDP协议。在选择使用协议的时候,选择UDP必须要谨慎。在网络质量令人不十分满意的环境下,UDP协议数据包丢失会比较严重。

三. 在Java中使用UDP协议编程的相关类
1. InetAddress
用于描述和包装一个Internet IP地址。有如下方法返回实例:
getLocalhost():返回封装本地地址的实例。

getAllByName(String host):返回封装Host地址的InetAddress实例数组。

getByName(String host):返回一个封装Host地址的实例。其中,Host可以是域名或者是一个合法的IP地址。
InetAddress.getByAddress(addr):根据地址串返回InetAddress实例。
InetAddress.getByAddress(host, addr):根据主机地符串和地址串返回InetAddress实例。

2. DatagramSocket
用于接收和发送UDP的Socket实例。该类有3个构造函数:
DatagramSocket():通常用于客户端编程,它并没有特定监听的端口,仅仅使用一个临时的。程序会让操作系统分配一个可用的端口。
DatagramSocket(int port):创建实例,并固定监听Port端口的报文。通常用于服务端

DatagramSocket(int port, InetAddress localAddr):这是个非常有用的构建器,当一台机器拥有多于一个IP地址的时候,由它创建的实例仅仅接收来自LocalAddr的报文。
DatagramSocket具有的主要方法如下:
1)receive(DatagramPacket d):接收数据报文到d中。receive方法产生一个“阻塞”。“阻塞”是一个专业名词,它会产生一个内部循环,使程序暂停在这个地方,直到一个条件触发。

2)send(DatagramPacket dp):发送报文dp到目的地。

3)setSoTimeout(int timeout):设置超时时间,单位为毫秒。

4)close():关闭DatagramSocket。在应用程序退出的时候,通常会主动释放资源,关闭Socket,但是由于异常地退出可能造成资源无法回收。所以,应该在程序完成时,主动使用此方法关闭Socket,或在捕获到异常抛出后关闭Socket。

3. DatagramPacket
用于处理报文,它将Byte数组、目标地址、目标端口等数据包装成报文或者将报文拆卸成Byte数组。应用程序在产生数据包是应该注意,TCP/IP规定数据报文大小最多包含65507个,通常主机接收548个字节,但大多数平台能够支持8192字节大小的报文。DatagramPacket类的构建器共有4个:
DatagramPacket(byte[] buf, int length):将数据包中Length长的数据装进Buf数组,一般用来接收客户端发送的数据。
DatagramPacket(byte[] buf, int offset, int length):将数据包中从Offset开始、Length长的数据装进Buf数组。
DatagramPacket(byte[] buf, int length, InetAddress clientAddress, int clientPort):从Buf数组中,取出Length长的数据创建数据包对象,目标是clientAddress地址,clientPort端口,通常用来发送数据给客户端。

DatagramPacket(byte[] buf, int offset, int length, InetAddress clientAddress, int clientPort):从Buf数组中,取出Offset开始的、Length长的数据创建数据包对象,目标是clientAddress地址,clientPort端口,通常用来发送数据给客户端。
主要的方法如下:
1)getData(): 从实例中取得报文的Byte数组编码。
2)setDate(byte[] buf):将byte数组放入要发送的报文中。
四. 实例解析
下面让我们来看一个UDP的服务端和客户端交互通信的例子,在本例中,服务端循环等待客户端发送的信息,并对其进行回应,客户端向服务端发送信息,并接收服务端的回应信息。代码如下:
1.UDP的服务端程序

[java] view plaincopyprint?
  1. import java.io.IOException;    
  2. import java.net.DatagramPacket;    
  3. import java.net.DatagramSocket;    
  4. import java.net.InetAddress;    
  5. import java.net.InetSocketAddress;    
  6. import java.net.SocketException;    
  7.     
  8. /**  
  9.  * Copyright 2007 GuangZhou Cotel Co. Ltd.  
  10.  * All right reserved.      
  11.  * UTP服务类.       
  12.  * @author QPING 
  13.  */    
  14. public class UdpServerSocket {    
  15.     private byte[] buffer = new byte[1024];    
  16.         
  17.     private DatagramSocket ds = null;    
  18.     
  19.     private DatagramPacket packet = null;    
  20.     
  21.     private InetSocketAddress socketAddress = null;    
  22.     
  23.     private String orgIp;    
  24.     
  25.     /**  
  26.      * 构造函数,绑定主机和端口.  
  27.      * @param host 主机  
  28.      * @param port 端口  
  29.      * @throws Exception  
  30.      */    
  31.     public UdpServerSocket(String host, int port) throws Exception {    
  32.         socketAddress = new InetSocketAddress(host, port);    
  33.         ds = new DatagramSocket(socketAddress);    
  34.         System.out.println("服务端启动!");    
  35.     }    
  36.         
  37.     public final String getOrgIp() {    
  38.         return orgIp;    
  39.     }    
  40.     
  41.     /**  
  42.      * 设置超时时间,该方法必须在bind方法之后使用.  
  43.      * @param timeout 超时时间  
  44.      * @throws Exception  
  45.      */    
  46.     public final void setSoTimeout(int timeout) throws Exception {    
  47.         ds.setSoTimeout(timeout);    
  48.     }    
  49.     
  50.     /**  
  51.      * 获得超时时间.  
  52.      * @return 返回超时时间.  
  53.      * @throws Exception  
  54.      */    
  55.     public final int getSoTimeout() throws Exception {    
  56.         return ds.getSoTimeout();    
  57.     }    
  58.     
  59.     /**  
  60.      * 绑定监听地址和端口.  
  61.      * @param host 主机IP  
  62.      * @param port 端口  
  63.      * @throws SocketException  
  64.      */    
  65.     public final void bind(String host, int port) throws SocketException {    
  66.         socketAddress = new InetSocketAddress(host, port);    
  67.         ds = new DatagramSocket(socketAddress);    
  68.     }    
  69.     
  70.     
  71.     /**  
  72.      * 接收数据包,该方法会造成线程阻塞.  
  73.      * @return 返回接收的数据串信息  
  74.      * @throws IOException   
  75.      */    
  76.     public final String receive() throws IOException {    
  77.         packet = new DatagramPacket(buffer, buffer.length);    
  78.         ds.receive(packet);    
  79.         orgIp = packet.getAddress().getHostAddress();    
  80.         String info = new String(packet.getData(), 0, packet.getLength());    
  81.         System.out.println("接收信息:" + info);    
  82.         return info;    
  83.     }    
  84.     
  85.     /**  
  86.      * 将响应包发送给请求端.  
  87.      * @param bytes 回应报文  
  88.      * @throws IOException  
  89.      */    
  90.     public final void response(String info) throws IOException {    
  91.         System.out.println("客户端地址 : " + packet.getAddress().getHostAddress()    
  92.                 + ",端口:" + packet.getPort());    
  93.         DatagramPacket dp = new DatagramPacket(buffer, buffer.length, packet    
  94.                 .getAddress(), packet.getPort());    
  95.         dp.setData(info.getBytes());    
  96.         ds.send(dp);    
  97.     }    
  98.     
  99.     /**  
  100.      * 设置报文的缓冲长度.  
  101.      * @param bufsize 缓冲长度  
  102.      */    
  103.     public final void setLength(int bufsize) {    
  104.         packet.setLength(bufsize);    
  105.     }    
  106.     
  107.     /**  
  108.      * 获得发送回应的IP地址.  
  109.      * @return 返回回应的IP地址  
  110.      */    
  111.     public final InetAddress getResponseAddress() {    
  112.         return packet.getAddress();    
  113.     }    
  114.     
  115.     /**  
  116.      * 获得回应的主机的端口.  
  117.      * @return 返回回应的主机的端口.  
  118.      */    
  119.     public final int getResponsePort() {    
  120.         return packet.getPort();    
  121.     }    
  122.     
  123.     /**  
  124.      * 关闭udp监听口.  
  125.      */    
  126.     public final void close() {    
  127.         try {    
  128.             ds.close();    
  129.         } catch (Exception ex) {    
  130.             ex.printStackTrace();    
  131.         }    
  132.     }    
  133.     
  134.     /**  
  135.      * 测试方法.  
  136.      * @param args  
  137.      * @throws Exception  
  138.      */    
  139.     public static void main(String[] args) throws Exception {    
  140.         String serverHost = "127.0.0.1";    
  141.         int serverPort = 3344;    
  142.         UdpServerSocket udpServerSocket = new UdpServerSocket(serverHost, serverPort);    
  143.         while (true) {    
  144.             udpServerSocket.receive();    
  145.             udpServerSocket.response("你好,sterning!");    
  146.                 
  147.         }    
  148.     }    
  149. }   

2. UDP客户端程序


[java] view plaincopyprint?
  1. import java.io.*;    
  2. import java.net.*;    
  3.     
  4. /**  
  5.  * Copyright 2007 GuangZhou Cotel Co. Ltd.  
  6.  * All right reserved.      
  7.  * UDP客户端程序,用于对服务端发送数据,并接收服务端的回应信息.  
  8.  * @author QPING 
  9.  */    
  10. public class UdpClientSocket {    
  11.     private byte[] buffer = new byte[1024];    
  12.     
  13.     private DatagramSocket ds = null;    
  14.     
  15.     /**  
  16.      * 构造函数,创建UDP客户端  
  17.      * @throws Exception  
  18.      */    
  19.     public UdpClientSocket() throws Exception {    
  20.         ds = new DatagramSocket();    
  21.     }    
  22.         
  23.     /**  
  24.      * 设置超时时间,该方法必须在bind方法之后使用.  
  25.      * @param timeout 超时时间  
  26.      * @throws Exception  
  27.      */    
  28.     public final void setSoTimeout(final int timeout) throws Exception {    
  29.         ds.setSoTimeout(timeout);    
  30.     }    
  31.     
  32.     /**  
  33.      * 获得超时时间.  
  34.      * @return 返回超时时间  
  35.      * @throws Exception  
  36.      */    
  37.     public final int getSoTimeout() throws Exception {    
  38.         return ds.getSoTimeout();    
  39.     }    
  40.     
  41.     public final DatagramSocket getSocket() {    
  42.         return ds;    
  43.     }    
  44.     
  45.     /**  
  46.      * 向指定的服务端发送数据信息.  
  47.      * @param host 服务器主机地址  
  48.      * @param port 服务端端口  
  49.      * @param bytes 发送的数据信息  
  50.      * @return 返回构造后俄数据报  
  51.      * @throws IOException  
  52.      */    
  53.     public final DatagramPacket send(final String host, final int port,    
  54.             final byte[] bytes) throws IOException {    
  55.         DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress    
  56.                 .getByName(host), port);    
  57.         ds.send(dp);    
  58.         return dp;    
  59.     }    
  60.     
  61.     /**  
  62.      * 接收从指定的服务端发回的数据.  
  63.      * @param lhost 服务端主机  
  64.      * @param lport 服务端端口  
  65.      * @return 返回从指定的服务端发回的数据.  
  66.      * @throws Exception  
  67.      */    
  68.     public final String receive(final String lhost, final int lport)    
  69.             throws Exception {    
  70.         DatagramPacket dp = new DatagramPacket(buffer, buffer.length);    
  71.         ds.receive(dp);    
  72.         String info = new String(dp.getData(), 0, dp.getLength());    
  73.         return info;    
  74.     }    
  75.     
  76.     /**  
  77.      * 关闭udp连接.  
  78.      */    
  79.     public final void close() {    
  80.         try {    
  81.             ds.close();    
  82.         } catch (Exception ex) {    
  83.             ex.printStackTrace();    
  84.         }    
  85.     }    
  86.     
  87.     /**  
  88.      * 测试客户端发包和接收回应信息的方法.  
  89.      * @param args  
  90.      * @throws Exception  
  91.      */    
  92.     public static void main(String[] args) throws Exception {    
  93.         UdpClientSocket client = new UdpClientSocket();    
  94.         String serverHost = "127.0.0.1";    
  95.         int serverPort = 3344;    
  96.         client.send(serverHost, serverPort, ("你好,阿蜜果!").getBytes());    
  97.         String info = client.receive(serverHost, serverPort);    
  98.         System.out.println("服务端回应数据:" + info);    
  99.     }    
  100. }   

Echo Server

An Echo Server Based on UDP Sockets

import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;/*from w w  w  . jav  a2  s. c o  m*/public class Main {  public static void main(String[] args) throws Exception {    final int LOCAL_PORT = 12345;    final String SERVER_NAME = "localhost";    DatagramSocket udpSocket = new DatagramSocket(LOCAL_PORT,        InetAddress.getByName(SERVER_NAME));    System.out.println("Created UDP  server socket at "        + udpSocket.getLocalSocketAddress() + "...");    while (true) {      System.out.println("Waiting for a  UDP  packet...");      DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);      udpSocket.receive(packet);      displayPacketDetails(packet);      udpSocket.send(packet);    }  }  public static void displayPacketDetails(DatagramPacket packet) {    byte[] msgBuffer = packet.getData();    int length = packet.getLength();    int offset = packet.getOffset();    int remotePort = packet.getPort();    InetAddress remoteAddr = packet.getAddress();    String msg = new String(msgBuffer, offset, length);    System.out.println("Received a  packet:[IP Address=" + remoteAddr        + ", port=" + remotePort + ", message=" + msg + "]");  }}




Echo Client

An Echo Client Based on UDP Sockets

//  w ww  .j  a va 2  s  . c  omimport java.io.BufferedReader;import java.io.InputStreamReader;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.net.UnknownHostException;public class Main {  public static void main(String[] args) throws Exception {    DatagramSocket udpSocket = new DatagramSocket();    String msg = null;    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));    System.out.print("Please enter a  message  (Bye  to quit):");    while ((msg = br.readLine()) != null) {      if (msg.equalsIgnoreCase("bye")) {        break;      }      DatagramPacket packet = Main.getPacket(msg);      udpSocket.send(packet);      udpSocket.receive(packet);      displayPacketDetails(packet);      System.out.print("Please enter a  message  (Bye  to quit):");    }    udpSocket.close();  }  public static void displayPacketDetails(DatagramPacket packet) {    byte[] msgBuffer = packet.getData();    int length = packet.getLength();    int offset = packet.getOffset();    int remotePort = packet.getPort();    InetAddress remoteAddr = packet.getAddress();    String msg = new String(msgBuffer, offset, length);    System.out.println("[Server at IP  Address=" + remoteAddr + ", port="        + remotePort + "]: " + msg);  }  public static DatagramPacket getPacket(String msg)      throws UnknownHostException {    int PACKET_MAX_LENGTH = 1024;    byte[] msgBuffer = msg.getBytes();    int length = msgBuffer.length;    if (length > PACKET_MAX_LENGTH) {      length = PACKET_MAX_LENGTH;    }    DatagramPacket packet = new DatagramPacket(msgBuffer, length);    InetAddress serverIPAddress = InetAddress.getByName("localhost");    packet.setAddress(serverIPAddress);    packet.setPort(15900);    return packet;  }}








0 0