《Java TCP/IP Socket编程》读书笔记(4)

2.3 UDP套接字

UDP协议提供了一种不同于TCP协议的端对端服务,实际上UDP只实现了两个功能:1)、 在IP协议的基础上添加了另一层地址(端口)2)、对数据传输过程中可能产生的错误进行了检测,并抛弃了已损坏的数据。

UDP套接字与TCP套接字的不同点:

1. UDP协议在使用前不需要进行连接。

2. UDP协议保存边界信息。

2.3.1 UDP客户端

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

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

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

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


DatagramSocket创建的时候不需要指定目的地址。因为UDP通信前不需要进行连接。每个数据报可以发送到或者接收于不同的目的地址。

UDP协议的一个后果是会出现数据报文丢失。为了避免这个问题,可以设置最大阻塞时间。

下面一个UDP客户端的例子

package com.suifeng.tcpip.chapter2;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

/**
 * UDP 客户端
 * 
 * @author Suifeng
 * 
 */
public class UDPEchoClientTimeout
{
	// 超时时间
	private static final int TIMEOUT = 3000;
	// 最大连接次数
	private static final int MAXTRIES = 5;

	public static void main(String[] args) throws IOException
	{
		if (args.length < 2 || args.length > 3)
		{
			throw new IllegalArgumentException(
					"Paramters:<Server> <Word> [<Port>]");
		}

		// 服务器地址
		InetAddress serverAddress = InetAddress.getByName(args[0]);

		// 要发送的数据
		byte[] byteToSend = args[1].getBytes();

		// 服务器端口
		int serverPort = (args.length == 3) ? Integer.parseInt(args[2]) : 7;

		// UDP客户端
		DatagramSocket socket = new DatagramSocket();
		// 接收数据阻塞时间
		socket.setSoTimeout(TIMEOUT);

		System.out.println("UDP 客户端已建立....");
		
		// 发送数据报包
		DatagramPacket sendPacket = new DatagramPacket(byteToSend,
				byteToSend.length, serverAddress, serverPort);

		// 接收的数据报包
		DatagramPacket receiverPacket = new DatagramPacket(
				new byte[byteToSend.length], byteToSend.length);

		// 尝试接收次数
		int tries = 0;
		boolean receivedResponse = false;

		do
		{
			System.out.println("向服务区端发送数据....");
			// 向服务器端发送数据
			socket.send(sendPacket);

			try
			{
				System.out.println("接收从服务器端返回的数据...");
				// 从服务器端接收数据
				socket.receive(receiverPacket);

				if (!receiverPacket.getAddress().equals(serverAddress))
				{
					throw new IOException(
							"Received packet from an unknown source");
				}

				receivedResponse = true;
			}
			catch (InterruptedIOException e)
			{
				tries++;
				System.out.println("Timed out," + (MAXTRIES - tries)
						+ " more ties");
			}

		} while ((!receivedResponse) && (tries < MAXTRIES));

		if(receivedResponse)
		{
			System.out.println("Received:"+new String(receiverPacket.getData()));
		}
		else
		{
			System.out.println("No response--giving up!");
		}
	}

}

2.3.2 UDP服务器端

TCP服务器一样,UDP服务器是建一个几个通信终端,并被动等待客户端发起连接。

典型的UDP服务器执行需要以下三步。

1. 创建一个DatagramSocket实例,指定本地端口号,并可以选择指定本地地址。此时,服务器已经准备好从任何客户端接收数据报文。

2. 使用DatagramSocket类的receive()方法来接收一个DatagramPacket实例。当receive()方法返回时,数据报文就包含了客户端的地址,这样我们就知道了回复信息应该发送到什么地方。

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


下面的例子是使用UDP将客户端发送过来的消息会发给客户端的。

package com.suifeng.tcpip.chapter2;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

/**
 * UDP服务器端
 * 
 * @author Suifeng
 * 
 */
public class UDPEchoServer
{

	// 最大显示数组字节数
	private static final int ECHO_MAX = 255;

	public static void main(String[] args) throws IOException
	{
		if (args.length != 1)
		{
			throw new IllegalArgumentException("Parameter:<Port>");
		}

		// 服务器端口
		int serverPort = Integer.parseInt(args[0]);
		
		// 服务器端
		DatagramSocket socket = new DatagramSocket(serverPort);
		
		// 数据报
		DatagramPacket packet = new DatagramPacket(new byte[ECHO_MAX], ECHO_MAX);
		System.out.println("UDP服务器已启动....");
		while (true)
		{
			System.out.println("正在等待客户端发送数据....");
			// 接收客户端发送的数据(阻塞)
			socket.receive(packet);

			System.out.println("Handing client at "
					+ packet.getAddress().getHostAddress() + " on port "
					+ packet.getPort());
			System.out.println("Received Data:"+new String(packet.getData()));
			
			// 向客户端发送数据(这里只是将数据包进行转发--透传,没有进行任何处理)
			socket.send(packet);
			// 重置缓存区大小
			packet.setLength(ECHO_MAX);
		}
	}

}

先启用服务器端,监听39393端口


在启用客户端发送数据


再查看服务器端


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值