赞
踩
在本 Java 网络编程教程中,您将学习如何编写基于 UDP 协议的客户端/服务器应用程序。
首先,让我们看看 Java Network API 是如何设计来支持使用 UDP 的网络应用程序开发的。
DatagramPacket 和DatagramSocket是用于实现 UDP 客户端/服务器应用程序的两个主要类。DatagramPacket是一个数据容器,DatagramSocket是一种发送和接收DatagramPacket的机制。
在 UDP 的术语中,传输的数据被封装在一个称为数据报的单元中。数据报是通过网络发送的一个独立的、自包含的消息,其到达、到达时间和内容都没有保证。而在 Java 中,DatagramPacket代表一个数据报。
您可以使用以下构造函数之一创建DatagramPacket对象:
如您所见,数据必须采用字节数组的形式。第一个构造函数用于创建要接收的DatagramPacket。
第二个构造函数创建了一个要发送的DatagramPacket,所以需要指定目的主机的地址和端口号。
参数 length 指定要使用的字节数组中的数据量,通常是数组的长度(buf.length)。
还有其他构造函数允许您指定字节数组中的偏移量,以及使用SocketAddress:
此外,DatagramPacket为地址、数据和端口号提供了 setter 和 getter 方法。有关完整的详细信息,请参阅其DatagramPacket Javadoc。
您使用DatagramSocket发送和接收DatagramPacket。DatagramSocket表示网络中两台计算机之间的 UDP 连接。
在 Java 中,我们对客户端和服务器都使用DatagramSocket。客户端和服务器没有单独的类,如 TCP 套接字。
因此,您可以使用以下构造函数之一创建一个DatagramSocket对象来建立用于发送和接收数据报的 UDP 连接:
无参数构造函数用于创建绑定到任意端口号的客户端。第二个构造函数用于创建绑定到特定端口号的服务器,以便客户端知道如何连接。
第三个构造函数将服务器绑定到指定的 IP 地址(以防计算机有多个 IP 地址)。
如果无法打开套接字,或者套接字无法绑定到指定的端口或地址,则这些构造函数可以抛出SocketException。所以你已经捕获或重新抛出这个已检查的异常。
DatagramSocket的关键方法包括:
这些方法可以抛出IOException、PortUnreachableException、SocketTimeoutException ……所以你必须捕捉或重新抛出它们。有关 完整的详细信息,请参阅 DatagramSocket Javadoc。
现在,让我们看看一些运行中的示例程序。
我们将为一个客户端程序编写代码,该程序从实现每日报价 (QOTD) 服务(一种 Internet 标准)的服务器请求报价。以下代码片段将DatagramPacket发送到由主机名和端口指定的服务器:
1
2
3
4
5
6
7
8
9
10
|
String hostname = "djxmmx.net" ;
int port = 17 ;
InetAddress address = InetAddress.getByName(hostname);
DatagramSocket socket = new DatagramSocket();
byte [] buffer = new byte [ 512 ];
DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, port);
socket.send(request);
|
如您所见,缓冲区没有数据,因为 QOTD 服务不需要客户端发送任何特定消息。并且您必须在DatagramPacket 中指定服务器的地址和端口。所以这段代码只是向服务器发送一个信号,暗示“嘿,我想从你那里得到一个报价”。
下面的代码片段从服务器接收一个DatagramPacket:
1
2
3
4
5
6
|
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
String quote = new String(buffer, 0 , response.getLength());
System.out.println(quote);
|
如您所见,一旦套接字打开,接收数据包非常简单。并且代码将字节数组转换为以可读格式打印的字符串。
这是完整客户端程序的代码,它参数化主机名和端口号,处理异常并每 10 秒从服务器获取报价:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
import java.io.*;
import java.net.*;
/**
* This program demonstrates how to implement a UDP client program.
*
*
* @author www.codejava.net
*/
public class QuoteClient {
public static void main(String[] args) {
if (args.length < 2 ) {
System.out.println( "Syntax: QuoteClient <hostname> <port>" );
return ;
}
String hostname = args[ 0 ];
int port = Integer.parseInt(args[ 1 ]);
try {
InetAddress address = InetAddress.getByName(hostname);
DatagramSocket socket = new DatagramSocket();
while ( true ) {
DatagramPacket request = new DatagramPacket( new byte [ 1 ], 1 , address, port);
socket.send(request);
byte [] buffer = new byte [ 512 ];
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
String quote = new String(buffer, 0 , response.getLength());
System.out.println(quote);
System.out.println();
Thread.sleep( 10000 );
}
} catch (SocketTimeoutException ex) {
System.out.println( "Timeout error: " + ex.getMessage());
ex.printStackTrace();
} catch (IOException ex) {
System.out.println( "Client error: " + ex.getMessage());
ex.printStackTrace();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
|
要测试此客户端程序,请键入以下命令:
1
|
java QuoteClient djxmmx.net 17
|
djxmmx.net是我们可以使用的公共QOTD服务器,17是为QOTD服务预留的端口号。
你会看到这样的输出:
1
2
3
4
5
6
7
|
"When a stupid man is doing something he is ashamed of, he always declares that it is his duty." George Bernard Shaw (1856-1950)
"Oh the nerves, the nerves; the mysteries of this machine called man!
Oh the little that unhinges it, poor creatures that we are!"
Charles Dickens (1812-70)
In Heaven an angel is nobody in particular." George Bernard Shaw (1856-1950)
|
如果您自己测试这个程序,您可能会看到不同的引号,因为服务器返回随机引号。按 Ctrl + C 终止程序。
下面的示例程序演示了如何为上述客户端实现服务器。以下代码创建一个 UDP 服务器,监听端口 17 并等待客户端的请求:
1
2
3
4
5
6
|
DatagramSocket socket = new DatagramSocket( 17 );
byte [] buffer = new byte [ 256 ];
DatagramPacket request = new DatagramPacket(buffer, buffer.length);
socket.receive(request);
|
的接收() ,直到接收到一个数据报的方法块。下面的代码向客户端发送一个DatagramPacket:
1
2
3
4
5
6
7
8
|
InetAddress clientAddress = request.getAddress();
int clientPort = request.getPort();
String data = "Message from server" ;
buffer = data.getBytes();
DatagramPacket response = new DatagramPacket(buffer, buffer.length, clientAddress, clientPort);
socket.send(response);
|
如您所见,服务器还需要知道客户端的地址和端口才能发送DatagramPacket。该信息可以从之前从客户端接收到的DatagramPacket 中获得。并且 String 被转换为一个字节数组,然后可以将其包装在DatagramPacket 中。
下面是一个功能齐全的服务器程序,它从文本文件中读取报价,并为每个客户端的请求发送一个随机报价。引用文件和端口号作为程序的参数给出。这是代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
import java.io.*;
import java.net.*;
import java.util.*;
/**
* This program demonstrates how to implement a UDP server program.
*
*
* @author www.codejava.net
*/
public class QuoteServer {
private DatagramSocket socket;
private List<String> listQuotes = new ArrayList<String>();
private Random random;
public QuoteServer( int port) throws SocketException {
socket = new DatagramSocket(port);
random = new Random();
}
public static void main(String[] args) {
if (args.length < 2 ) {
System.out.println( "Syntax: QuoteServer <file> <port>" );
return ;
}
String quoteFile = args[ 0 ];
int port = Integer.parseInt(args[ 1 ]);
try {
QuoteServer server = new QuoteServer(port);
server.loadQuotesFromFile(quoteFile);
server.service();
} catch (SocketException ex) {
System.out.println( "Socket error: " + ex.getMessage());
} catch (IOException ex) {
System.out.println( "I/O error: " + ex.getMessage());
}
}
private void service() throws IOException {
while ( true ) {
DatagramPacket request = new DatagramPacket( new byte [ 1 ], 1 );
socket.receive(request);
String quote = getRandomQuote();
byte [] buffer = quote.getBytes();
InetAddress clientAddress = request.getAddress();
int clientPort = request.getPort();
DatagramPacket response = new DatagramPacket(buffer, buffer.length, clientAddress, clientPort);
socket.send(response);
}
}
private void loadQuotesFromFile(String quoteFile) throws IOException {
BufferedReader reader = new BufferedReader( new FileReader(quoteFile));
String aQuote;
while ((aQuote = reader.readLine()) != null ) {
listQuotes.add(aQuote);
}
reader.close();
}
private String getRandomQuote() {
int randomIndex = random.nextInt(listQuotes.size());
String randomQuote = listQuotes.get(randomIndex);
return randomQuote;
}
}
|
假设我们有一个Quotes.txt文件,其中包含以下内容(每个引号都在一行中):
1
2
3
4
5
|
Whether you think you can or you think you can't, you're right - Henry Ford
There are no traffic jams along the extra mile - Roger Staubach
Build your own dreams, or someone else will hire you to build theirs - Farrah Gray
What you do today can improve all your tomorrows - Ralph Marston
Remember that not getting what you want is sometimes a wonderful stroke of luck - Dalai Lama
|
键入以下命令以运行服务器程序:
1
|
java QuoteServer Quotes.txt 17
|
并运行客户端程序(在同一台计算机上):
1
|
java QuoteClient localhost 17
|
客户端和服务器都在无限循环中运行,因此您必须按 Ctrl + C 终止。
这就是关于如何开发依赖 UDP 协议的网络客户端/服务器应用程序的课程。基于这些知识,您可以开发通过 UDP 与服务器通信的客户端程序,并开发您自己的 UDP 客户端/服务器应用程序。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。