UDP网络编程简单实现

由于最近编写的游戏涉及到了网络编程这块,所以特意记录下。

UDP简介

UDP协议的全称是用户数据报,在网络中它与TCP协议一样用于处理数据报。在OSI模型中,UDP位于第四层——传输层,处于IP协议额上一层。UDP有不提供数据报分组、组装以及不能对数据报排序的缺点。当报文发送之后,是无法得知其是否安全完整到达的。

由于UDP不属于连接性协议的特性,因此具有资源消耗小、处理速度快的优点,所以通过音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响,如人们聊天使用的ICQ和OICQ使用的就是UDP协议。

使用java.net包下的DatagramSocket和DatagramPacket类,可以非常方便地控制用户数据报文。下面就对这两个类进行介绍

DatagramPacket类

DatagramPacket类用于处理报文,他将byte数组、目标地址和目标端口等数据包装成报文或者将报文拆卸成byte数组。

DatagramPacket有多个构造方法,通常情况下它们都有两个共同的参数:byte[] buffer和int length。其中buffer参数包含了一个对保存自寻址数据报信息的字节数组的引用,length表示字节数组的长度。

最简单的构造方法是:

DatagramPacket(byte[] buffer,int length);

这个构造方法确定了数据报数组和数组的长度,但没有任何数据报的地址和端口信息,这些信息可以通过调用方法setAddress(InetAddress addr)和setPort(int port)添加。下面代码示范这些方法的使用:

byte[] buffer = new byte[100];
DatagramPacket dgp = new DatagramPacket(buffer,buffer.length);
InetAddress address = InetAddress.getByName("www.disney.com");
dgp.setAddress(address);
dgp.setPort(6666);//设置数据报发送端口

如果用户更喜欢在调用构造方法时同时包括地址和端口号,则可以使用:

DatagramPacket(byte[] buffer,int length,InetAddress address,int port);

如果在创建DatagramPacket对象后想要改变字节数组和它的长度,可以通过setData()和setLength()方法进行修改:

setData(byte[] buffer);
setLength(int length);

DatagramPacket类的常用方法如下:

扫描二维码关注公众号,回复: 4742432 查看本文章

getAddress()、setAddress(InetAddress address):得到、设置数据博地址

getData()、setData(byte[] buffer):得到、设置数据报内容

getLength()、setLength(int length):得到、设置数据报长度

getPort()、setPort(int port)得到、设置端口号

DatagramSocket类

DatagramSocket类在客户端创建数据报套接字与服务端进行通信连接,并发送和接受数据报套接字。

客户端套接字最常用的构造方法是DatagramSocket()函数,而服务器端则是DatagramSocket(int port)函数。如果未能创建套接字或者绑定套接字到本地端口,那么这两个函数都将抛出一个SocketException异常,一旦程序创建了DatagramSocket对象,那么程序分别调用send(DatagramPacket p)和receive(DatagramPacket p)来发送和接受数据报。

DatagramSocket构造方法如下:

DatagramSocket():创建数据报套接字,绑定到本地任意存在的端口;

DatagramSocket(int port):创建数据报套接字,绑定到本地主机指定端口;

DatagramSocket(int port,InetAddress address):创建数据报套接字,绑定到指定本地地址。

常用方法如下:

connect(InetAddress address,int port):连接指定地址

disconnect():断开套接字连接

close():关闭数据报套接字

getInetAddress():得到套接字所连接的主机地址

getLocalAddress():得到套接字绑定的主机地址

getLocalPort():得到套接字的端口号

receive(DatagramPacket p):接收数据报

send(DatagramPacket p):发送数据报。

实践

实现一个简单的双向聊天的功能:

创建两个类:Client类和Server类

初始状况下,双方都处于空闲状态,客户端窗口和服务端窗口输入文字按下回车后,对方的窗口能及时显示对方发送过来的消息。

实现思路:

两个类的代码可以大量复用,创建两个数据报套接字sendSocket和receiveSocket,其中sendSocket用来发送消息,而receiveSocket用来接收消息;实现Runnable接口,创建线程持续监听receiveSocket监听的端口是否有发送来消息,如果有则控制台进行消息的打印。创建一个Scanner对象,持续读取控制台输入,如果控制台输入完毕并回车,则调用send方法将输入的消息封装到数据报然后发送到对方监听的端口。这里服务端监听3002端口,客户端监听3001,代码实现如下:

Server类:

package 网络编程;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class Server implements Runnable{

	DatagramSocket sendSocket;
	DatagramSocket receiveSocket;
	
	public Server(){		
	
		try {
			receiveSocket = new DatagramSocket(3002);
			sendSocket = new DatagramSocket();
		} catch (Exception e) {
			e.printStackTrace();
		}
		new Thread(this).start();
	}
	
	
	
	public static void main(String[] args) {
		System.out.println("服务端|空闲中...");
		Server server = new Server();
		Scanner input = new Scanner(System.in);
		while(true){
			String s =  input.next();
			server.send(s);
		}
		
	}

	public void send(String str){

		try {
			byte[] buffer;
			buffer = str.getBytes();
			InetAddress ia;
			ia = InetAddress.getByName("127.0.0.1");
			DatagramPacket dgp = new DatagramPacket(buffer,buffer.length,ia,3001);
			sendSocket.send(dgp);

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	
	@Override
	public void run() {
	
		byte[] data = new byte[100];
		DatagramPacket dgp = new DatagramPacket(data,data.length);
		while(true){
		try {
			receiveSocket.receive(dgp);
			System.out.println("客户端|"+new String(data));
			for(int i=0;i<100;i++)
				data[i] = 0;
		} catch (IOException e) {
			e.printStackTrace();
		}
		}
	}


	

}

Client类:

package 网络编程;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

public class Client implements Runnable{

	DatagramSocket sendSocket;
	DatagramSocket receiveSocket;
	
	public Client(){

		try {
			receiveSocket = new DatagramSocket(3001);
			sendSocket = new DatagramSocket();
		} catch (Exception e) {
			e.printStackTrace();
		}
		Thread t = new Thread(this);
		t.start();
	}
	
	public static void main(String[] args) {
		System.out.println("客户端|空闲中...");
		Client client =	new Client();
		Scanner input = new Scanner(System.in);
		while(true){
			String s =  input.next();
			client.send(s);
		}
	}
	
	public void send(String str){

		try {
			byte[] buffer;
			buffer = str.getBytes();
			InetAddress ia;
			ia = InetAddress.getByName("127.0.0.1");
			DatagramPacket dgp = new DatagramPacket(buffer,buffer.length,ia,3002);
			sendSocket.send(dgp);

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	@Override
	public void run() {
		byte[] data = new byte[100];
		DatagramPacket dgp = new DatagramPacket(data,data.length);
		while(true){
		try {
			receiveSocket.receive(dgp);
			System.out.println("服务端|"+new String(data));
			for(int i=0;i<100;i++)
				data[i] = 0;
		} catch (IOException e) {
			e.printStackTrace();
		}
		}
	}

}

运行效果如图:

猜你喜欢

转载自blog.csdn.net/A1344714150/article/details/85495088