天天看点

java TCP/IP Socket编程-----基本套接字-----UDP通讯-----笔记6

概述:

UDP协议提供了一种不同于TCP协议的端到端服务。实际上UDP协议只实现两个功能:

1)在IP协议的基础上添加了另一层地址(端口),

2)对数据传输过程中可能产生的数据错误进行了检测,并抛弃已经损坏的数据。由于其简单性,UDP套接字具有一些与我们之前所看到的TCP套接字不同的特征。例如,UDP套接字在使用前不需要进行连接。TCP协议与电话通信相似,而UDP协议则与邮件通信相似:你寄包裹或信件时不需要进行"连接",但是你得为每个包裹和信件指定目的地址。类似的,每条信息(即数据报文,datagram)负载了自己的地址信息,并与其他信息相互独立。在接收信息时,UDP套接字扮演的角色就像是一个信箱,从不同地址发送来的信件和包裹都可以放到里面。一旦被创建,UDP套接字就可以用来连续地向不同的地址发送信息,或从任何地址接收信息。

1.API了解

DatagramPacket:创建

DatagramPacket(byte[ ] data, int length)

DatagramPacket(byte[ ] data, int offset, int length)

DatagramPacket(byte[ ] data, int length, InetAddress remoteAddr, int remotePort)

DatagramPacket(byte[ ] data, int offset, int length, InetAddress remoteAddr, int remotePort)

DatagramPacket(byte[ ] data, int length, SocketAddress sockAddr) DatagramPacket(byte[ ] data, int offset, int length, SocketAddress sockAddr)

DatagramPacket:地址处理

InetAddress getAddress() 

void setAddress(InetAddress address) 

int getPort() 

void setPort(int port) 

SocketAddress getSocketAddress()

void setSocketAddress(SocketAddress sockAddr)

DatagramPacket 处理数据

int getLength() 

void setLength(int length) 

int getOffset() 

byte[ ] getData()

 void setData(byte[ ] data) 

void setData(byte[ ] buffer, int offset, int length)

2.UDP客户端:

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

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

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

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

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

如果超过了指定时间仍未得到响应,客户端就会重发回馈请求。我们的回馈客户端执行以下步骤:

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

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

3. 终止客户端。

package com.tcp.ip.chapter2;

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

public class UDPEchoClientTimeout {

	private static final int TIMEOUT = 3000;
	private static final int MAXRIES = 5;
	
	public static void main(String[] args) throws Exception {
		if((args.length < 2) || (args.length > 3)) {
			throw new IllegalArgumentException("Parameter(s) : <Server> <Word> [<Port>]");
			
		}
		InetAddress serverAddress = InetAddress.getByName(args[0]);
		byte [] bytesToSend = args[1].getBytes();
		int servPort = (args.length == 3) ? Integer.parseInt(args[2]) : 7;
		
		DatagramSocket socket = new DatagramSocket();
		socket.setSoTimeout(TIMEOUT);
		DatagramPacket sendPacket = new DatagramPacket(bytesToSend, bytesToSend.length,serverAddress, servPort);
		DatagramPacket receivePacket =new DatagramPacket(new byte[bytesToSend.length], bytesToSend.length);
		//如果发送失败还要继续发
		int tries = 0;
		boolean receivedResponse = false;
		do {
			socket.send(sendPacket);
			try {socket.receive(receivePacket);
			if(!receivePacket.getAddress().equals(serverAddress)) {
				throw new IOException("Received packet from an unknownsource");
			}
			receivedResponse = true;
			} catch (InterruptedIOException e) {
				tries +=1;
				System.out.println("Timed out," + (MAXRIES-tries) + " more tries");
			}
		}while ((!receivedResponse) && (tries < MAXRIES));
			
		if(receivedResponse) {
			System.out.println("接受数据成功:" + new String(receivePacket.getData()));
		}else {
			System.out.println("接受数据失败");
		}
		socket.close();
	}
}
           

2.常用的API

DatagramSocket: 创建

DatagramSocket() 

DatagramSocket(int localPort)

 DatagramSocket(int localPort, InetAddress localAddr)

DatagramSocket: 连接与关闭

void connect(InetAddress remoteAddr, int remotePort) 

void connect(SocketAddress remoteSockAddr) 

void disconnect()

void close()

DatagramSocket: 地址处理

InetAddress getInetAddress() 

int getPort() 

SocketAddress getRemoteSocketAddress()

 InetAddress getLocalAddress()

 int getLocalPort() SocketAddress

 getLocalSocketAddress()

DatagramSocket: 发送和接收

void send(DatagramPacket packet) 

void receive(DatagramPacket packet)

DatagramSocket: 选项

int getSoTimeout() 

void setSoTimeout(int timeoutMillis)

3.UDP服务器端

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

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

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

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

package com.tcp.ip.chapter2;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPEchoServer {

	private static final int ECHOMAX = 255;
	public static void main(String[] args) throws Exception {
		if(args.length != 1) {
			throw new IllegalArgumentException("Parameter(s): <Port>");
			
		}
		int servPort = Integer.parseInt(args[0]);
		
		DatagramSocket socket = new DatagramSocket(servPort);
		DatagramPacket packet = new DatagramPacket(new byte[ECHOMAX], ECHOMAX);
		while (true) {
			socket.receive(packet);
			System.out.println("Handling client at " + packet.getAddress().getHostAddress()
					+ " on port " + packet.getPort());
			socket.send(packet);
			packet.setLength(ECHOMAX);
		}
		
	}
}
           

DatagramSocket就是像快递员,没有打电话通知你,可能第一次他去你家,你不在,他就是回去了,下一次再来,你又不在家,一直到⑤次还不在,他认为你拒收了。