`

UDP带重连的客户端

阅读更多
===========转载========
2.3.2 UDP客户端
2009-02-15 15:48 周恒民 机械工业出版社 我要评论(0) 字号:T | T
综合评级:想读(6)  在读(0)  已读(6)   品书斋鉴(1)   已有12人发表书评

《Java TCP/IP Socket编程》第2章基本套接字,本章讲述的是如何编写自己的套接字应用程序了。本节为大家介绍的是UDP客户端。
AD: 51CTO云计算架构师峰会 抢票进行中!
2.3.2 UDP客户端

UDP客户端首先向被动等待联系的服务器端发送一个数据报文。一个典型的UDP客户端主要执行以下三步:

1. 创建一个DatagramSocket实例,可以选择对本地地址和端口号进行设置。

2. 使用DatagramSocket类的send() 和 receive()方法来发送和接收DatagramPacket实例,进行通信。

3. 通信完成后,使用DatagramSocket类的close()方法来销毁该套接字。

与Socket类不同,DatagramSocket实例在创建时并不需要指定目的地址。这也是TCP协议和UDP协议的最大不同点之一。在进行数据交换前,TCP套接字必须跟特定主机和另一个端口号上的TCP套接字建立连接,之后,在连接关闭前,该套接字就只能与相连接的那个套接字通信。而UDP套接字在进行通信前则不需要建立连接,每个数据报文都可以发送到或接收于不同的目的地址。(DatagramSocket类的connect()方法确实允许指定远程地址和端口,但该功能是可选的。)

我们的UDP回馈客户端示例程序UDPEchoClientTimeout.java,发送一个带有回馈字符串的数据报文,并打印出从服务器收到的所有信息。一个UDP回馈服务器只是简单地将其收到的数据报文返回给客户端。当然,一个UDP客户端只与一个UDP服务器进行通信。许多系统都集成了UDP回馈服务程序,用于调试和测试。

使用UDP协议的一个后果是数据报文可能丢失。在我们的回馈协议中,客户端的回馈请求信息和服务器端的响应信息都有可能在网络中丢失。回顾前面所介绍的TCP回馈客户端,其发送了一个回馈字符串后,将在read()方法上阻塞等待响应。如果试图在我们的UDP回馈客户端上使用相同的策略,数据报文丢失后,我们的客户端就会永远阻塞在receive()方法上。为了避免这个问题,我们在客户端使用DatagramSocket类的setSoTimeout()方法来指定receive()方法的最长阻塞时间,因此,如果超过了指定时间仍未得到响应,客户端就会重发回馈请求。我们的回馈客户端执行以下步骤:

1. 向服务器端发送回馈字符串。

2. 在receive()方法上最多阻塞等待3秒钟,在超时前若没有收到响应,则重发请求(最多重发5次)。

3. 终止客户端。

UDPEchoClientTimeout.java

0 import java.net.DatagramSocket;
1 import java.net.DatagramPacket;
2 import java.net.InetAddress;
3 import java.io.IOException;
4 import java.io.InterruptedIOException;
5
6 public class UDPEchoClientTimeout {
7
8 private static final int TIMEOUT = 3000; // Resend timeout (milliseconds)
9 private static final int MAXTRIES = 5; // Maximum retransmissions
10
11 public static void main(String[] args) throws IOException {
12
13 if ((args.length < 2) || (args.length > 3)) { // Test for correct # of args
14 throw new IllegalArgumentException("Parameter(s): <Server> <Word> [<Port>]");
15 }
16 InetAddress serverAddress = InetAddress.getByName(args[0]); // Server address
17 // Convert the argument String to bytes using the default encoding
18 byte[] bytesToSend = args[1].getBytes();
19
20 int servPort = (args.length == 3) ? Integer.parseInt(args[2]) : 7;
21
22 DatagramSocket socket = new DatagramSocket();
23
24 socket.setSoTimeout(TIMEOUT); // Maximum receive blocking time (milliseconds)
25
26 DatagramPacket sendPacket = new DatagramPacket(bytesToSend, // Sending packet
27 bytesToSend.length, serverAddress, servPort);
28
29 DatagramPacket receivePacket = // Receiving packet
30 new DatagramPacket(new byte[bytesToSend.length], bytesToSend.length);
31
32 int tries = 0; // Packets may be lost, so we have to keep trying
33 boolean receivedResponse = false;
34 do {
35 socket.send(sendPacket); // Send the echo string
36 try {
37 socket.receive(receivePacket); // Attempt echo reply reception
38
39 if (!receivePacket.getAddress().equals(serverAddress)) {// Check source
40 throw new IOException("Received packet from an unknown source");
41 }
42 receivedResponse = true;
43 } catch (InterruptedIOException e) { // We did not get anything
44 tries += 1;
45 System.out.println("Timed out, " + (MAXTRIES - tries) + " more tries...");
46 }
47 } while ((!receivedResponse) && (tries < MAXTRIES));
48
49 if (receivedResponse) {
50 System.out.println("Received: " + new String(receivePacket.getData()));
51 } else {
52 System.out.println("No response -- giving up.");
53 }
54 socket.close();
55 }
56 }
UDPEchoClientTimeout.java

1. 应用程序设置和参数解析:第0-20行

2. 创建UDP套接字:第22行

该DatagramSocket实例能够将数据报文发送给任何UDP套接字。我们没有指定本地地址和端口号,因此程序将自动选择本地地址和可用端口号。如果需要的话,我们也可以通过setLocalAddress()和setLocalPort()方法或构造函数,来显式地设置本地地址和端口。

3. 设置套接字超时时间:第24行

数据报文套接字的超时时间,用来控制调用receive()方法的最长阻塞时间(毫秒)。本例中我们设置超时时间为3秒。注意,超时时间是不精确的,receive()方法的调用可能会阻塞比这更长的时间(但不会少于超时时间)。

4. 创建发送的数据报文:第26-27

创建一个要发送的数据报文,我们需要指定三件事:数据,目的地址,以及目的端口。对于目的地址,我们可以使用主机名或IP地址来确定一个回馈服务器。若使用的是主机名,它将在构造函数中转换成实际的IP地址。

5. 创建接收的数据报文:第29-30行

创建一个要接收的数据报文,我们只需要定义一个用来存放报文数据的字节数组。而数据报文的源地址和端口号将从receive()方法获得。

6. 发送数据报文:第32-47行

由于数据报文可能丢失,我们必须准备好重新传输数据。本例中,我们最多循环5次,来发送数据报文并尝试接收响应信息。

发送数据报文:第35行

send()方法将数据报文传输到其指定的地址和端口号去。

处理数据报文的接收:第36-46行

receive()方法将阻塞等待,直到收到一个数据报文或等待超时。超时信息由InterruptedIOException异常指示。一旦超时,发送尝试计数器(tries))加1,并重新发送。若尝试了最大次数后,仍没有接收到数据报文,循环将退出。如果receive()方法成功接收了数据,我们将循环标记receivedResponse设为true,以退出循环。由于数据报文可能发送自任何地址,我们需要验证所接收的数据报文,检查其源地址和端口号是否与所指定的回馈服务器地址和端口号相匹配。

7. 打印接收结果:第49-53行

如果接收到了一个数据报文,即receivedResponse为true,我们就可以打印出数据报文中的数据信息。

8. 关闭套接字:第54行

在学习服务器端代码之前,我们先看看DatagramSocket类的主要方法。

DatagramSocket: 创建

DatagramSocket()
DatagramSocket(int localPort)
DatagramSocket(int localPort, InetAddress localAddr)
以上构造函数将创建一个UDP套接字。可以分别或同时设置本地端口和地址。如果没有指定本地端口,或将其设置为0,该套接字将与任何可用的本地端口绑定。如果没有指定本地地址, 数据包(packet)可以接收发送向任何本地地址的数据报文。

DatagramSocket: 连接与关闭

void connect(InetAddress remoteAddr, int remotePort)
void connect(SocketAddress remoteSockAddr)
void disconnect()
void close()

connect()方法用来设置套接字的远程地址和端口。一旦连接成功,该套接字就只能与指定的地址和端口进行通信,任何向其他地址和端口发送数据报文的尝试都将抛出一个异常。套接字也将只接收从指定地址和端口发送来的数据报文,从其他地址或端口发送来的数据报文将被忽略。重点提示:连接到多播地址或广播地址的套接字只能发送数据报文,因为数据报文的源地址总是一个单播地址(见第4.3节)。注意,连接仅仅是本地操作,因为与TCP协议不同,UDP中没有端对端的数据包交换。disconnect()方法用来清空远程地址和端口号,若存在的话。close()方法表明该套接字不再使用,之后任何发送或接收数据的尝试都将抛出异常。
DatagramSocket: 地址处理

InetAddress getInetAddress()
int getPort()
SocketAddress getRemoteSocketAddress()
InetAddress getLocalAddress()
int getLocalPort()
SocketAddress getLocalSocketAddress()
第一个方法返回一个代表所连接的远程套接字地址的InetAddress实例,如果没有连接,则返回null。与之类似,getPort()方法返回所连接的套接字的端口号,若没有连接则返回-1。第三个方法一个SocketAddress实例,其中包含了所连接的远程套接字的地址和端口号,如果没有连接,则返回null。

后面三个方法为本地地址和端口提供了类似的服务。如果该套接字没有与本地地址绑定,getLocalAddress()方法将返回通配符地址("任何本地地址")。getLocalPort()方法总是会返回一个本地端口号。如果调用这个方法前该套接字还没有绑定端口号,getLocalPort()方法将选择任意一个可以本地端口与之绑定。getLocalSocketAddress()在套接字没有绑定本地地址时返回null。

DatagramSocket: 发送和接收

void send(DatagramPacket packet)
void receive(DatagramPacket packet)

send()方法用来发送DatagramPacket实例。一旦建立连接,数据包将发送到该套接字所连接的地址,除非DatagramPacket实例中已经指定了不同目的地址,这将抛出一个异常。如果没有创建连接,数据包将发送到DatagramPacket实例中指定的目的地址。该方法不阻塞等待。
receive()方法将阻塞等待,直到接收到数据报文,并将报文中的数据复制到指定的DatagramPacket实例中。如果套接字已经创建了连接,该方法也阻塞等待,直到接收到从所连接的远程套接字发来的数据报文。

DatagramSocket: 选项

int getSoTimeout()
void setSoTimeout(int timeoutMillis)

以上方法分别获取和设置该套接字中receive()方法调用的最长阻塞时间。如果在接收到数据之前超时,则抛出InterruptedIOException异常。超时时间以毫秒为单位。
与Socket类和ServerSocket类一样,DatagramSocket类也还有许多其他选项,这些内容将在第4.4节更加完整地介绍。
分享到:
评论

相关推荐

    UDP socket自动连接客户端

    两台或多台android设备,其中有一台作为服务端,则另外一台或几台作为客户端,然后通过UDP进行自动连接.其实现的原理很简单,服务端这一边通过MulticastSocket将自己的有关信息,如IP,端口等广播出去,同一个广播地址里面...

    libevent实现UDP relay服务器与客户端

    需要注意的是,由于UDP的特性,服务器和客户端都需要考虑数据包的丢失、乱序和重复等问题,可能需要自定义重传机制或顺序恢复策略。 在项目中,`libevent-client`和`libevent-server`分别代表了客户端和服务器的源...

    基于udp和tcp的客户端和服务器

    本项目“基于udp和tcp的客户端和服务器”涉及C++编程语言,利用socket接口实现这两种协议的客户端与服务器端的交互。 TCP是一种面向连接的、可靠的传输协议,它确保了数据包的顺序传输和错误检测。在TCP通信中,...

    基于UDP协议的unity客户端,内涵服务端源码

    标题中的“基于UDP协议的unity客户端,内涵服务端源码”揭示了这是一个关于使用Unity引擎开发的客户端程序,它依赖于用户数据协议(UDP)来与远程服务器进行通信。UDP是一种无连接的传输层协议,相比TCP,它不提供...

    稳定版本tcp/udp iocp服务器及客户端

    在UDP/iOCp客户端中,数据被封装成UDP报文,通过IOCP异步发送到服务器,同时,客户端也会通过IOCP监听来自服务器的UDP报文,确保在高并发环境下仍能高效处理数据。 在提供的"myRudp"文件中,可能包含了实现TCP和UDP...

    头歌UDP Ping程序实现-客户端创建UDP套接字

    头歌UDP Ping程序实现-客户端创建UDP套接字头歌UDP Ping程序实现-客户端创建UDP套接字头歌UDP Ping程序实现-客户端创建UDP套接字头歌UDP Ping程序实现-客户端创建UDP套接字头歌UDP Ping程序实现-客户端创建UDP套接...

    c# UDP 多线程 多客户端传输例子

    本示例将探讨如何在C#中实现一个支持多线程和多客户端的UDP服务器和客户端。 首先,让我们详细解析标题中的"多线程"概念。在多线程编程中,程序可以同时执行多个任务,提高资源利用率和响应速度。在处理多个客户端...

    UDP通信服务器和客户端 VC++

    "UDP通信服务器和客户端 VC++" 在这篇文章中,我们将讨论如何使用VC++语言实现UDP通信服务器和客户端的开发。UDP(User Datagram Protocol)是一种无连接的网络协议,用于在网络上发送数据包。 UDP通信服务器端 ...

    基于MFC的UDP打洞通信客户端

    7. **异常处理与断线重连**:考虑到网络的不稳定性,需要添加适当的错误处理和断线重连机制,确保通信的稳定性和可靠性。 8. **界面反馈**:在MFC对话框上添加状态显示,如连接状态、数据传输速度等,提升用户体验...

    在QT下的UDP服务器和客户端的简单DEMO

    QT是一个流行的开源C++图形用户界面应用程序开发框架,它提供了丰富的功能来构建桌面和移动平台...然而,实际的UDP服务器和客户端可能需要处理更复杂的情况,比如多客户端连接、数据包排序和重传、安全性和性能优化等。

    基于UDP协议通信的简单客户端/服务器

    本主题将深入探讨一种常见的网络通信协议——用户数据报协议(UDP),以及如何使用C#编程语言来实现基于UDP协议的简单客户端与服务器。 **UDP协议简介** UDP是一种无连接的传输层协议,它不像TCP那样建立连接后再...

    VC++版稳定高效tcp/udp iocp服务器及客户端

    本项目“VC++版稳定高效tcp/udp iocp服务器及客户端”正是基于这种机制构建的,旨在提供一种能够处理高负载、高并发网络通信的解决方案。 首先,我们来了解一下TCP(传输控制协议)和UDP(用户数据报协议)。TCP是...

    Unity UDP服务端和客户端代码

    - 这个脚本用于创建一个UDP客户端,它首先需要初始化一个`UdpClient`对象,用于发送和接收数据报文。 - `Initialize()` 方法通常用于设置目标服务器的IP地址和端口号,并启动监听。 - `SendData()` 方法用于封装...

    UDP_char.zip_udp 服务 客户_udp 聊天_udp客户端

    在标题“UDP_char.zip_udp 服务 客户_udp 聊天_udp客户端”中,我们可以理解为这是一个关于UDP聊天工具的项目,它包含了服务端和客户端的实现。这个工具可能允许在同一局域网内的用户通过UDP协议进行实时通信,如...

    UDP客户端_winsocket的UDP客户端_sangdiy_

    UDP客户端在Windows操作系统中通常指的是使用Winsock API(Windows Socket接口)实现的用户数据报协议(User Datagram Protocol)通信程序。Winsock是Windows系统提供的一个应用程序编程接口,它允许程序员直接与TCP...

    简单的UDP客户端+服务端的实现

    本项目“简单的UDP客户端+服务端的实现”是一个基于Java的maven项目,旨在帮助初学者理解UDP通信的基本原理和实践方法。该项目包含了一些辅助工具类,如`byteutil`和IP解析工具类,以方便数据的编码解码和IP地址的...

    UDP服务器和客户端程序

    UDP客户端和服务器需要考虑如何重组这些分片数据,或者避免大块数据的发送。 6. **多线程/并发处理**:为了处理多个并发连接,服务器端可能需要使用多线程或多进程,每个线程或进程处理一个特定的客户端连接。 7. ...

    C#编程socket编程之udp服务器端和客户端

    基于Udp协议是无连接模式通讯,占用资源少,响应速度快,延时低。至于可靠性,可通过应用层的控制来满足。(不可靠连接)使用Udp协议通讯需要具备以下几个条件:(1).建立一个套接字(Socket)(2).绑定服务器端IP地址及...

    modbus-udp连接客户端

    udp客户端连接案例,有解码器,适用与modbus协议的udp连接客户端

    用UDP实现客户端与服务器的连接

    本项目通过VC++编程环境,利用WinSock2库实现了基于UDP的客户端与服务器的通信。 首先,我们来看`UDPKeShe`,这可能是服务器端的代码。在服务器端,首先需要初始化WinSock库,这个过程通常通过调用`WSAStartup`函数...

Global site tag (gtag.js) - Google Analytics