计算机网络是指两台或更多的计算机组成的网络,在同一个网络中,任意两台计算机都可以直接通信,因为所有计算机都需要遵循同一种网络协议。网络编程中有很多协议,如,TCP协议、UDP协议。顾名思义,UDP编程就是以UDP协议为基础的编程。
和TCP编程相比,UDP编程就简单得多,因为UDP没有创建连接,数据包也是一次收发一个,所以没有流的概念。
在Java中使用UDP编程,仍然需要使用Socket,因为应用程序在使用UDP时必须指定网络接口(IP地址)和端口号。注意:UDP端口和TCP端口虽然都使用0~65535,但他们是两套独立的端口,即一个应用程序用TCP占用了端口1234,不影响另一个应用程序用UDP占用端口1234。
在服务器端,使用UDP也需要监听指定的端口。Java提供了DatagramSocket来实现这个功能,服务器端首先要监听一个指定的端口(如1234端口),如果没有其他应用程序占据这个端口,那么监听成功,我们就使用一个无限循环来处理收到的UDP数据包,若要接收一个packet数据包,我们需要根据接收数据的大小创建一个byte[ ]缓冲区,然后通过Dategrampacket实现接收;假设我们收取到的是一个String,那么,通过DatagramPacket返回的packet.getOffset()和packet.getLength()确定数据在缓冲区的开始位置和结束位置,在下面的代码中,我们需要把接收到的字节数组转化为字符串,然后作为key(键)在创建的map中得到相应的value(值),因为怕发送至客户端时出现空指针异常,我们可以在得到value(值)后,可以做一个判断,如果值为null,则给value赋值为一个提示,让客户端重新输入一个map中存在的值,然后进行后面的发送操作。一般当服务器收到一个DatagramPacket后,通常必须立刻回复一个或多个UDP包,因为客户端地址在DatagramPacket中,每次收到的DatagramPacket可能是不同的客户端,如果不回复,客户端就收不到任何UDP包。 发送UDP包也是通过DatagramPacket实现的。发送UDP数据包时,我们需要把从map中得到的字符串利用*.getBytes()方法变成一个字符串数组,然后通过DatagramPacket发送至客户端。具体代码实现如下:
package com.hpc.wyj02;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.HashMap;
import java.util.Map;
/**
* 服务器
* @author 我
*
*/
public class Demo02 {
public static void main(String[] args) {
Map<String, String> map=new HashMap<String, String>(){
{
put("one","一");
put("two","二");
put("three","三");
put("four","四");
}
};
//服务器端监听1234端口
try (DatagramSocket serverSocket = new DatagramSocket(1234)) {
while(true) {
//准备“空”数据包
byte[] buff=new byte[1024]; //原始的字节数组
DatagramPacket packet=new DatagramPacket(buff, buff.length);
//读取(客户端发送的英文单词)
//接收数据包
serverSocket.receive(packet);
//获取数据包中的“数据”(字节数组):packet.getData()
//获取数据包中的“读取位置”(int类型):packet.getOffset()
//获取数据包中的“长度”:packet.getLength()
String s=new String(packet.getData(), packet.getOffset(),
packet.getLength());
System.out.println("来自客户端的单词:"+s);
String chinese=map.get(s);
if(chinese==null) {
chinese="请重新输入!";
}
byte[] chinesebuff=chinese.getBytes();
packet.setData(chinesebuff);
serverSocket.send(packet);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在客户端,和服务器端相比,客户端使用UDP时,只需要直接向服务器端发送UDP包,然后接收返回的UDP包。首先,客户端需要创建一个DatagramSocket对象,客户端创建DatagramSocket实例时并不需要指定端口,而是由操作系统自动指定一个当前未使用的端口。紧接着,调用setSoTimeout(1000)设定超时1秒,意思是后续接收UDP包时,等待时间最多不会超过1秒,否则在没有收到UDP包时,客户端会无限等待下去。这一点和服务器端不一样,服务器端可以无限等待,因为它本来就被设计成长时间运行。注意到客户端的DatagramSocket还调用了一个connect()方法“连接”到指定的服务器端。这个connect()方法不是真连接,它是为了在客户端的DatagramSocket实例中保存服务器端的IP和端口号,确保这个DatagramSocket实例只能往指定的地址和端口发送UDP包,不能往其他地址和端口发送。这么做不是UDP的限制,而是Java内置了安全检查。如果客户端希望向多个不同的服务器发送UDP包,那么它必须创建多个DatagramSocket实例。后续的收发数据和服务器端是一致的。通常来说,客户端必须先发UDP包,因为客户端不发UDP包,服务器端就根本不知道客户端的地址和端口号。如果客户端认为通信结束,就可以调用disconnect()断开连接。注意:disconnect()也不是真正地断开连接,它只是清除了客户端DatagramSocket实例记录的远程服务器地址和端口号.这样,DatagramSocket实例就可以连接另一个服务器端。客户端的实现代码如下:
package com.hpc.wyj02;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Scanner;
public class Demo01 {
/**
* 客户端
* @param args
*/
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
while(true) {
String s=input.nextLine(); //英文单词
if(s.equals("over")) {
System.out.println("运行完毕!");
break;
}
//创建基于UDP协议的DatagramSocket对象
try (DatagramSocket cilentSocekt = new DatagramSocket()) {
//timeout超时
cilentSocekt.setSoTimeout(20000);
//连接服务器(服务器IP和端口)
cilentSocekt.connect(new InetSocketAddress("192.168.0.104",1234));
//发送(向服务器发送一个英文单词)
byte[] buff=s.getBytes(); //获取英文单词字符串的字节数组
//封装成DatagramPacket对象(数据包)
DatagramPacket cilentPacket=new DatagramPacket(buff,buff.length);
//发送数据包
cilentSocekt.send(cilentPacket);
byte[] resultbuff=new byte[1024];
DatagramPacket resultPacket=new DatagramPacket(resultbuff,
resultbuff.length);
cilentSocekt.receive(resultPacket);
String result=new String(resultPacket.getData(),
resultPacket.getOffset(), resultPacket.getLength());
System.out.println("来自服务器的回答:"+result);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
版权归原作者 望远雾 所有, 如有侵权,请联系我们删除。