文章推荐

精选java等全套视频教程

精选java电子图书

大数据视频教程精选

java项目练习精选

网络编程UDP

网络通讯的方式除了TCP方式以外,还有一种实现的方式就是UDP方式。UDP(User Datagram Protocol),中文意思是用户数据报协议,方式类似于发短信息,是一种物美价廉的通讯方式,使用该种方式无需建立专用的虚拟连接,由于无需建立专用的连接,所以对于服务器的压力要比TCP小很多,所以也是一种常见的网络编程方式。但是使用该种方式最大的不足是传输不可靠,当然也不是说经常丢失,就像大家发短信息一样,理论上存在收不到的可能,这种可能性可能是1%,反正比较小,但是由于这种可能的存在,所以平时我们都觉得重要的事情还是打个电话吧(类似TCP方式),一般的事情才发短信息(类似UDP方式)。网络编程中也是这样,必须要求可靠传输的信息一般使用TCP方式实现,一般的数据才使用UDP方式实现。

UDP方式的网络编程也在Java语言中获得了良好的支持,由于其在传输数据的过程中不需要建立专用的连接等特点,所以在Java API中设计的实现结构和TCP方式不太一样。当然,需要使用的类还是包含在java.net包中。

在Java API中,实现UDP方式的编程,包含客户端网络编程和服务器端网络编程,主要由两个类实现,分别是:

DatagramSocket

DatagramSocket类实现“网络连接”,包括客户端网络连接和服务器端网络连接。虽然UDP方式的网络通讯不需要建立专用的网络连接,但是毕竟还是需要发送和接收数据,DatagramSocket实现的就是发送数据时的发射器,以及接收数据时的监听器的角色。类比于TCP中的网络连接,该类既可以用于实现客户端连接,也可以用于实现服务器端连接。

DatagramPacket

DatagramPacket类实现对于网络中传输的数据封装,也就是说,该类的对象代表网络中交换的数据。在UDP方式的网络编程中,无论是需要发送的数据还是需要接收的数据,都必须被处理成DatagramPacket类型的对象,该对象中包含发送到的地址、发送到的端口号以及发送的内容等。其实DatagramPacket类的作用类似于现实中的信件,在信件中包含信件发送到的地址以及接收人,还有发送的内容等,邮局只需要按照地址传递即可。在接收数据时,接收到的数据也必须被处理成DatagramPacket类型的对象,在该对象中包含发送方的地址、端口号等信息,也包含数据的内容。和TCP方式的网络传输相比,IO编程在UDP方式的网络编程中变得不是必须的内容,结构也要比TCP方式的网络编程简单一些。

下面介绍一下UDP方式的网络编程中,客户端和服务器端的实现步骤,以及通过基础的示例演示UDP方式的网络编程在Java语言中的实现方式。

UDP方式的网络编程,编程的步骤和TCP方式类似,只是使用的类和方法存在比较大的区别,下面首先介绍一下UDP方式的网络编程客户端实现过程。

UDP客户端编程涉及的步骤也是4个部分:建立连接、发送数据、接收数据和关闭连接。

首先介绍UDP方式的网络编程中建立连接的实现。其中UDP方式的建立连接和TCP方式不同,只需要建立一个连接对象即可,不需要指定服务器的IP和端口号码。实现的代码为:

     DatagramSocket ds = new DatagramSocket();

这样就建立了一个客户端连接,该客户端连接使用系统随机分配的一个本地计算机的未用端口号。在该连接中,不指定服务器端的IP和端口,所以UDP方式的网络连接更像一个发射器,而不是一个具体的连接。

当然,可以通过制定连接使用的端口号来创建客户端连接。

                   DatagramSocket ds = new DatagramSocket(5000);

这样就是使用本地计算机的5000号端口建立了一个连接。一般在建立客户端连接时没有必要指定端口号码。

接着,介绍一下UDP客户端编程中发送数据的实现。在UDP方式的网络编程中,IO技术不是必须的,在发送数据时,需要将需要发送的数据内容首先转换为byte数组,然后将数据内容、服务器IP和服务器端口号一起构造成一个DatagramPacket类型的对象,这样数据的准备就完成了,发送时调用网络连接对象中的send方法发送该对象即可。例如将字符串“Hello”发送到IP是127.0.0.1,端口号是10001的服务器,则实现发送数据的代码如下:

      String s = “Hello”;String host = “127.0.0.1”;int port = 10001;//将发送的内容转换为byte数组byte[] b = s.getBytes();//将服务器IP转换为InetAddress对象InetAddress server = InetAddress.getByName(host);//构造发送的数据包对象DatagramPacket sendDp = new DatagramPacket(b,b.length,server,port);//发送数据ds.send(sendDp);

在该示例代码中,不管发送的数据内容是什么,都需要转换为byte数组,然后将服务器端的IP地址构造成InetAddress类型的对象,在准备完成以后,将这些信息构造成一个DatagramPacket类型的对象,在UDP编程中,发送的数据内容、服务器端的IP和端口号,都包含在DatagramPacket对象中。在准备完成以后,调用连接对象ds的send方法把DatagramPacket对象发送出去即可。

按照UDP协议的约定,在进行数据传输时,系统只是尽全力传输数据,但是并不保证数据一定被正确传输,如果数据在传输过程中丢失,那就丢失了。

UDP方式在进行网络通讯时,也遵循“请求-响应”模型,在发送数据完成以后,就可以接收服务器端的反馈数据了。

下面介绍一下UDP客户端编程中接收数据的实现。当数据发送出去以后,就可以接收服务器端的反馈信息了。接收数据在Java语言中的实现是这样的:首先构造一个数据缓冲数组,该数组用于存储接收的服务器端反馈数据,该数组的长度必须大于或等于服务器端反馈的实际有效数据的长度。然后以该缓冲数组为基础构造一个DatagramPacket数据包对象,最后调用连接对象的receive方法接收数据即可。接收到的服务器端反馈数据存储在DatagramPacket类型的对象内部。实现接收数据以及显示服务器端反馈内容的示例代码如下:

     //构造缓冲数组byte[] data = new byte[1024];//构造数据包对象DatagramPacket received = new DatagramPacket(data,data.length);//接收数据ds.receive(receiveDp);//输出数据内容byte[] b = receiveDp.getData(); //获得缓冲数组int len = receiveDp.getLength(); //获得有效数据长度String s = new String(b,0,len);System.out.println(s);

在该代码中,首先构造缓冲数组data,这里设置的长度1024是预估的接收到的数据长度,要求该长度必须大于或等于接收到的数据长度,然后以该缓冲数组为基础,构造数据包对象,使用连接对象ds的receive方法接收反馈数据,由于在Java语言中,除String以外的其它对象都是按照地址传递,所以在receive方法内部可以改变数据包对象receiveDp的内容,这里的receiveDp的功能和返回值类似。数据接收到以后,只需要从数据包对象中读取出来就可以了,使用DatagramPacket对象中的getData方法可以获得数据包对象的缓冲区数组,但是缓冲区数组的长度一般大于有效数据的长度,换句话说,也就是缓冲区数组中只有一部分数据是反馈数据,所以需要使用DatagramPacket对象中的getLength方法获得有效数据的长度,则有效数据就是缓冲数组中的前有效数据长度个内容,这些才是真正的服务器端反馈的数据的内容。

UDP方式客户端网络编程的最后一个步骤就是关闭连接。虽然UDP方式不建立专用的虚拟连接,但是连接对象还是需要占用系统资源,所以在使用完成以后必须关闭连接。关闭连接使用连接对象中的close方法即可,实现的代码如下:

                   ds.close();

需要说明的是,和TCP建立连接的方式不同,UDP方式的同一个网络连接对象,可以发送到达不同服务器端IP或端口的数据包,这点是TCP方式无法做到的。

介绍完了UDP方式客户端网络编程的基础知识以后,下面再来介绍一下UDP方式服务器端网络编程的基础知识。

UDP方式网络编程的服务器端实现和TCP方式的服务器端实现类似,也是服务器端监听某个端口,然后获得数据包,进行逻辑处理以后将处理以后的结果反馈给客户端,最后关闭网络连接,下面依次进行介绍。

首先UDP方式服务器端网络编程需要建立一个连接,该连接监听某个端口,实现的代码为:

    DatagramSocket ds = new DatagramSocket(10010);

由于服务器端的端口需要固定,所以一般在建立服务器端连接时,都指定端口号。例如该示例代码中指定10010端口为服务器端使用的端口号,客户端端在连接服务器端时连接该端口号即可。

接着服务器端就开始接收客户端发送过来的数据,其接收的方法和客户端接收的方法一直,其中receive方法的作用类似于TCP方式中accept方法的作用,该方法也是一个阻塞方法,其作用是接收数据。

接收到客户端发送过来的数据以后,服务器端对该数据进行逻辑处理,然后将处理以后的结果再发送给客户端,在这里发送时就比客户端要麻烦一些,因为服务器端需要获得客户端的IP和客户端使用的端口号,这个都可以从接收到的数据包中获得。示例代码如下:

    //获得客户端的IPInetAddress clientIP = receiveDp.getAddress();//获得客户端的端口号Int clientPort = receiveDp.getPort();

使用以上代码,就可以从接收到的数据包对象receiveDp中获得客户端的IP地址和客户端的端口号,这样就可以在服务器端中将处理以后的数据构造成数据包对象,然后将处理以后的数据内容反馈给客户端了。

最后,当服务器端实现完成以后,关闭服务器端连接,实现的方式为调用连接对象的close方法,示例代码如下:

      ds.close();

介绍完了UDP方式下的客户端编程和服务器端编程的基础知识以后,下面通过一个简单的示例演示UDP网络编程的基本使用。

该示例的功能是实现将客户端程序的系统时间发送给服务器端,服务器端接收到时间以后,向客户端反馈字符串“OK”。实现该功能的客户端代码如下所示:

package udp;
import java.net.*;
import java.util.*;
/*** 简单的UDP客户端,实现向服务器端发生系统时间功能*/
public class SimpleUDPClient {public static void main(String[] args) {DatagramSocket ds = null; //连接对象DatagramPacket sendDp; //发送数据包对象DatagramPacket receiveDp; //接收数据包对象String serverHost = "127.0.0.1"; //服务器IPint serverPort = 10010; //服务器端口号try{//建立连接ds = new DatagramSocket();//初始化发送数据Date d = new Date(); //当前时间String content = d.toString(); //转换为字符串byte[] data = content.getBytes();//初始化发送包对象InetAddress address = InetAddress.getByName(serverHost);sendDp = new DatagramPacket(data,data.length,address,serverPort);//发送ds.send(sendDp);//初始化接收数据byte[] b = new byte[1024];receiveDp = new DatagramPacket(b,b.length);//接收ds.receive(receiveDp);//读取反馈内容,并输出byte[] response = receiveDp.getData();int len = receiveDp.getLength();String s = new String(response,0,len);System.out.println("服务器端反馈为:" + s);}catch(Exception e){e.printStackTrace();}finally{try{//关闭连接ds.close();}catch(Exception e){}}}}

在该示例代码中,首先建立UDP方式的网络连接,然后获得当前系统时间,这里获得的系统时间是客户端程序运行的本地计算机的时间,然后将时间字符串以及服务器端的IP和端口,构造成发送数据包对象,调用连接对象ds的send方法发送出去。在数据发送出去以后,构造接收数据的数据包对象,调用连接对象ds的receive方法接收服务器端的反馈,并输出在控制台。最后在finally语句块中关闭客户端网络连接。

和下面将要介绍的服务器端一起运行时,客户端程序的输出结果为:

  服务器端反馈为:OK

下面是该示例程序的服务器端代码实现:

      package udp;import java.net.*;/*** 简单UDP服务器端,实现功能是输出客户端发送数据,并反馈字符串“OK"给客户端*/public class SimpleUDPServer {public static void main(String[] args) {DatagramSocket ds = null; //连接对象DatagramPacket sendDp; //发送数据包对象DatagramPacket receiveDp; //接收数据包对象final int PORT = 10010; //端口try{//建立连接,监听端口ds = new DatagramSocket(PORT);System.out.println("服务器端已启动:");//初始化接收数据byte[] b = new byte[1024];receiveDp = new DatagramPacket(b,b.length);//接收ds.receive(receiveDp);//读取反馈内容,并输出InetAddress clientIP = receiveDp.getAddress();int clientPort = receiveDp.getPort();byte[] data = receiveDp.getData();int len = receiveDp.getLength();System.out.println("客户端IP:" + clientIP.getHostAddress());System.out.println("客户端端口:" + clientPort);System.out.println("客户端发送内容:" + new String(data,0,len));//发送反馈String response = "OK";byte[] bData = response.getBytes();sendDp = new DatagramPacket(bData,bData.length,clientIP,clientPort);//发送ds.send(sendDp);}catch(Exception e){e.printStackTrace();}finally{try{//关闭连接ds.close();}catch(Exception e){}}}}

在该服务器端实现中,首先监听10010号端口,和TCP方式的网络编程类似,服务器端的receive方法是阻塞方法,如果客户端不发送数据,则程序会在该方法处阻塞。当客户端发送数据到达服务器端时,则接收客户端发送过来的数据,然后将客户端发送的数据内容读取出来,并在服务器端程序中打印客户端的相关信息,从客户端发送过来的数据包中可以读取出客户端的IP以及客户端端口号,将反馈数据字符串“OK”发送给客户端,最后关闭服务器端连接,释放占用的系统资源,完成程序功能示例。

和前面TCP方式中的网络编程类似,这个示例也仅仅是网络编程的功能示例,也存在前面介绍的客户端无法进行多次数据交换,以及服务器端不支持多个客户端的问题,这两个问题也需要对于代码进行处理才可以很方便的进行解决。

在解决该问题以前,需要特别指出的是UDP方式的网络编程由于不建立虚拟的连接,所以在实际使用时和TCP方式存在很多的不同,最大的一个不同就是“无状态”。该特点指每次服务器端都收到信息,但是这些信息和连接无关,换句话说,也就是服务器端只是从信息是无法识别出是谁发送的,这样就要求发送信息时的内容需要多一些,这个在后续的示例中可以看到。

下面是实现客户端多次发送以及服务器端支持多个数据包同时处理的程序结构,实现的原理和TCP方式类似,在客户端将数据的发送和接收放入循环中,而服务器端则将接收到的每个数据包启动一个专门的线程进行处理。实现的代码如下:

 package udp;import java.net.*;import java.util.*;/*** 简单的UDP客户端,实现向服务器端发生系统时间功能* 该程序发送3次数据到服务器端*/public class MulUDPClient {public static void main(String[] args) {DatagramSocket ds = null; //连接对象DatagramPacket sendDp; //发送数据包对象DatagramPacket receiveDp; //接收数据包对象String serverHost = "127.0.0.1"; //服务器IPint serverPort = 10012; //服务器端口号try{//建立连接ds = new DatagramSocket();//初始化InetAddress address = InetAddress.getByName(serverHost);byte[] b = new byte[1024];receiveDp = new DatagramPacket(b,b.length);System.out.println("客户端准备完成");//循环30次,每次间隔0.01秒for(int i = 0;i < 30;i++){//初始化发送数据Date d = new Date(); //当前时间String content = d.toString(); //转换为字符串byte[] data = content.getBytes();//初始化发送包对象sendDp = new DatagramPacket(data,data.length,address, serverPort);//发送ds.send(sendDp);//延迟Thread.sleep(10);//接收ds.receive(receiveDp);//读取反馈内容,并输出byte[] response = receiveDp.getData();int len = receiveDp.getLength();String s = new String(response,0,len);System.out.println("服务器端反馈为:" + s);}}catch(Exception e){e.printStackTrace();}finally{try{//关闭连接ds.close();}catch(Exception e){}}}}

在该示例中,将和服务器端进行数据交换的逻辑写在一个for循环的内部,这样就可以实现和服务器端的多次交换了,考虑到服务器端的响应速度,在每次发送之间加入0.01秒的时间间隔。最后当数据交换完成以后关闭连接,结束程序。

实现该逻辑的服务器端程序代码如下:

package udp;
import java.net.*;
/**
* 可以并发处理数据包的服务器端
* 功能为:显示客户端发送的内容,并向客户端反馈字符串“OK”
*/
public class MulUDPServer {
public static void main(String[] args) {
DatagramSocket ds = null; //连接对象
DatagramPacket receiveDp; //接收数据包对象
final int PORT = 10012; //端口
byte[] b = new byte[1024];
receiveDp = new DatagramPacket(b,b.length);
try{
//建立连接,监听端口
ds = new DatagramSocket(PORT);
System.out.println("服务器端已启动:");
while(true){
//接收
ds.receive(receiveDp);
//启动线程处理数据包
new LogicThread(ds,receiveDp);
}
}catch(Exception e){e.printStackTrace();
}finally{
try{
//关闭连接
ds.close();
}catch(Exception e){}
}
}
}

该代码实现了服务器端的接收逻辑,使用一个循环来接收客户端发送过来的数据包,当接收到数据包以后启动一个LogicThread线程处理该数据包。这样服务器端就可以实现同时处理多个数据包了。

实现逻辑处理的线程代码如下:

package udp;
import java.net.*;
/*** 逻辑处理线程*/
public class LogicThread extends Thread {
/**连接对象*/
DatagramSocket ds;
/**接收到的数据包*/
DatagramPacket dp;
public LogicThread(DatagramSocket ds,DatagramPacket dp){
this.ds = ds;
this.dp = dp;
start(); //启动线程
}
public void run(){
try{
//获得缓冲数组
byte[] data = dp.getData();
//获得有效数据长度
int len = dp.getLength();
//客户端IP
InetAddress clientAddress = dp.getAddress();
//客户端端口
int clientPort = dp.getPort();
//输出
System.out.println("客户端IP:" + clientAddress.getHostAddress());
System.out.println("客户端端口号:" + clientPort);
System.out.println("客户端发送内容:" + new String(data,0,len));
//反馈到客户端
byte[] b = "OK".getBytes();
DatagramPacket sendDp = new DatagramPacket(b,b.length,clientAddress,clientPort);
//发送
ds.send(sendDp);
}catch(Exception e){
e.printStackTrace();
}
}
}

在该线程中,只处理一次UDP通讯,当通讯结束以后线程死亡,在线程内部,每次获得客户端发送过来的信息,将获得的信息输出到服务器端程序的控制台,然后向客户端反馈字符串“OK”。

由于UDP数据传输过程中可能存在丢失,所以在运行该程序时可能会出现程序阻塞的情况。如果需要避免该问题,可以将客户端的网络发送部分也修改成线程实现。

关于基础的UDP网络编程就介绍这么多了,下面将介绍一下网络协议的概念。

好好学java

推送java优质文章、视频教程

转自:http://www.cnblogs.com/springcsc/archive/2009/12/03/1616413.html
文章有不当之处,欢迎指正,你也可以关注我的微信公众号:好好学java

java网络编程(四)相关推荐

  1. Java网络编程(四)—— ServerSocket(一)

    Java网络编程(四)-- ServerSocket(一) Java网络编程(四)-- ServerSocket(一) 总述 创建ServerSocket 绑定端口 使用ServerSocket 总述 ...

  2. Java网络编程(第四版)

    网站 更多书籍点击进入>> CiCi岛 下载 电子版仅供预览及学习交流使用,下载后请24小时内删除,支持正版,喜欢的请购买正版书籍 电子书下载(皮皮云盘-点击"普通下载" ...

  3. Java课程实验报告 实验四 Java网络编程及安全

    北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计     班级:1352     姓名:吕松鸿  学号:20135229 成绩:               ...

  4. 【Java】 Java网络编程总结

     一.网络编程三要素: IP地址:每个设备在网络中的唯一标识. 端口号:每个程序在设备上的唯一标识. 协议:为计算机网络中进行数据交换而建立的规则或约定的集合. UDP: 面向无连接,数据不安全,速度 ...

  5. NIO详解(一):java网络编程IO总结(BIO、NIO、AIO)

    1.基本概念 在Java网络通信中,最基本的概念就是Socket编程了.Socket又称"套接字" 向网络发出请求或者应答网络请求. Socket 和ServerSocket类库位 ...

  6. 04.Java网络编程(转载)

    1.网络编程 1.1计算机网络概述 网络编程的实质就是两个(或多个)设备(例如计算机)之间的数据传输. 按照计算机网络的定义,通过一定的物理设备将处于不同位置的计算机连接起来组成的网络,这个网络中包含 ...

  7. 你所需要的java网络编程大总结

    好好学java java知识分享/学习教程免费分享 关注 精彩内容 你所需要的java全套视频教程 你所需要的java电子图书 你所需要的大数据视频教程 你所需要的java练习项目 如 / 梦 上个月 ...

  8. java网络编程(二)

    注意:架构师学习资源已更新. 获取方式:在公众号内回复"架构师资源" 文章推荐 精选java等全套视频教程 精选java电子图书 大数据视频教程精选 1.2 网络编程技术 前面介绍 ...

  9. 【带你入门】java网络编程

    网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编 ...

  10. 迈入JavaWeb第一步,Java网络编程基础,TCP网络编程URL网络编程等

    文章目录 网络编程概述 网络通信要素 要素一IP和端口号 要素二网络协议 TCP网络编程 UDP网络编程 URL网络编程 Java网络编程基础 网络编程概述 Java是Internet上的语言,它从语 ...

最新文章

  1. 机器视觉工程师必须了解的基础知识
  2. CAPI3 HTTP文件服务器搭建(共享目录版)
  3. User Profile Service 服务未能登录转载自(sailing的新浪博客)
  4. 无插件Vim编程技巧
  5. 云原生时代,Java还是Go?
  6. 假笨说-我是如何走上JVM这条贼船的
  7. 用C#编写ActiveX控件
  8. 成大事必备9种能力 9种手段 9种心态(图)
  9. Socket TCP和UDP的区别
  10. HDU 4740 The Donkey of Gui Zhou (模拟)
  11. Dual-arm cooperation and implementing for robotic harvesting tomato using binocular vision(摘西红柿机器人)
  12. 加速ASP.NET Core WEB API应用程序——第1部分
  13. Debug学习资源汇总
  14. POJ 2054 Color a Tree#贪心(难,好题)
  15. Atitit.Gui控件and面板----db数据库区----- .数据库比较同步工具 vOa
  16. matlab切片操作
  17. MFC分析工具—Resource Hacker
  18. Error: The method ‘DioHttpHeaders.add‘ has fewer named arguments than those of overridden method
  19. php 浏览器 保存网页图片,PHP实现浏览器文件下载图片或者php文件
  20. Affinity Photo2022比PS更好用的图像编辑软件

热门文章

  1. Shell Basic
  2. TensorFlow基于minist数据集实现手写字识别实战的三个模型
  3. Day03-卷积神经网络原理与使用
  4. android6鼠标驱动,USB鼠标按键驱动(示例代码)
  5. python 语言教程(2)基础语法
  6. Hyperledger Besu(3)“多用户架构”和“插件”
  7. 跨链Cosmos(5)ABCI 接口
  8. 6. Qt 信号与信号槽(11)Qt::ConnectionType类型
  9. java元婴期(24)----java进阶(mybatis(3)---动态sql(重点))
  10. 增量式爬虫与分布式爬虫