Java编程那些事儿106——网络编程技能5
副标题#e#
该示例的成果是实现将客户端措施的系统时间发送给处事器端,处事器端吸收到时间今后,向客户端反馈字符串“OK”。实现该成果的客户端代码如下所示:
package udp;
import java.net.*;
import java.util.*;
/**
* 简朴的UDP客户端,实现向处事器端产生系统时间成果
*/
public class SimpleUDPClient {
public static void main(String[] args) {
DatagramSocket ds = null; //毗连工具
DatagramPacket sendDp; //发送数据包工具
DatagramPacket receiveDp; //吸收数据包工具
String serverHost = "127.0.0.1"; //处事器IP
int serverPort = 10010; //处事器端标语
try{
//成立毗连
ds = new DatagramSocket();
//初始化发送数据
Date d = new Date(); //当前时间
String content = d.toString(); //转换为字符串
byte[] data = content.getBytes();
//初始化发送包工具
InetAddress address = InetAddress.getByName(serverHost);
sendDp = new DatagramPacket(data,data.length,address,serverPort);
//发送
ds.send(sendDp);
//初始化吸收数据
byte[] b = new byte[1024];
receiveDp = new DatagramPacket(b,b.length);
//吸收
ds.receive(receiveDp);
//读取反馈内容,并输出
byte[] response = receiveDp.getData();
int len = receiveDp.getLength();
String s = new String(response,0,len);
System.out.println("处事器端反馈为:" + s);
}catch(Exception e){
e.printStackTrace();
}finally{
try{
//封锁毗连
ds.close();
}catch(Exception e){}
}
}
}
#p#副标题#e#
在该示例代码中,首先成立UDP方法的网络毗连,然后获恰当前系统时间,这里得到的系统时间是客户端措施运行的当地计较机的时间,然后将时间字符串以及处事器端的IP和端口,结构成发送数据包工具,挪用毗连工具ds的send要领发送出去。在数据发送出去今后,结构吸收数据的数据包工具,挪用毗连工具ds的receive要领吸收处事器端的反馈,并输出在节制台。最后在finally语句块中封锁客户端网络毗连。
和下面将要先容的处事器端一起运行时,客户端措施的输出功效为:
处事器端反馈为:OK
下面是该示例措施的处事器端代码实现:
package udp;
import java.net.*;
/**
* 简朴UDP处事器端,实现成果是输出客户端发送数据,
并反馈字符串“OK"给客户端
*/
public class SimpleUDPServer {
public static void main(String[] args) {
DatagramSocket ds = null; //毗连工具
DatagramPacket sendDp; //发送数据包工具
DatagramPacket receiveDp; //吸收数据包工具
final int PORT = 10010; //端口
try{
//成立毗连,监听端口
ds = new DatagramSocket(PORT);
System.out.println("处事器端已启动:");
//初始化吸收数据
byte[] b = new byte[1024];
receiveDp = new DatagramPacket(b,b.length);
//吸收
ds.receive(receiveDp);
//读取反馈内容,并输出
InetAddress clientIP = receiveDp.getAddress();
int clientPort = receiveDp.getPort();
byte[] data = receiveDp.getData();
int len = receiveDp.getLength();
System.out.println("客户端IP:" + clientIP.getHostAddress());
System.out.println("客户端端口:" + clientPort);
System.out.println("客户端发送内容:" + new String(data,0,len));
//发送反馈
String response = "OK";
byte[] bData = response.getBytes();
sendDp = new DatagramPacket(bData,bData.length,clientIP,clientPort);
//发送
ds.send(sendDp);
}catch(Exception e){
e.printStackTrace();
}finally{
try{
//封锁毗连
ds.close();
}catch(Exception e){}
}
}
}
在该处事器端实现中,首先监听10010号端口,和TCP方法的网络编程雷同,处事器端的receive要领是阻塞要领,假如客户端不发送数据,则措施会在该要领处阻塞。当客户端发送数据达随处事器端时,则吸收客户端发送过来的数据,然后将客户端发送的数据内容读取出来,并在处事器端措施中打印客户端的相关信息,从客户端发送过来的数据包中可以读取出客户端的IP以及客户端端标语,将反馈数据字符串“OK”发送给客户端,最后封锁处事器端毗连,释放占用的系统资源,完成措施成果示例。
#p#分页标题#e#
和前面TCP方法中的网络编程雷同,这个示例也仅仅是网络编程的成果示例,也存在前面先容的客户端无法举办多次数据互换,以及处事器端不支持多个客户端的问题,这两个问题也需要对付代码举办处理惩罚才可以很利便的举办办理。
在办理该问题以前,需要出格指出的是UDP方法的网络编程由于不成立虚拟的毗连,所以在实际利用时和TCP方法存在许多的差异,最大的一个差异就是“无状态”。该特点指每次处事器端都收到信息,可是这些信息和毗连无关,换句话说,也就是处事器端只是从信息是无法识别出是谁发送的,这样就要求发送信息时的内容需要多一些,这个在后续的示例中可以看到。
下面是实现客户端多次发送以及处事器端支持多个数据包同时处理惩罚的措施布局,实现的道理和TCP方法雷同,在客户端将数据的发送和吸收放入轮回中,而处事器端则将吸收到的每个数据包启动一个专门的线程举办处理惩罚。实现的代码如下:
package udp;
import java.net.*;
import java.util.*;
/**
* 简朴的UDP客户端,实现向处事器端产生系统时间成果
* 该措施发送3次数据随处事器端
*/
public class MulUDPClient {
public static void main(String[] args) {
DatagramSocket ds = null; //毗连工具
DatagramPacket sendDp; //发送数据包工具
DatagramPacket receiveDp; //吸收数据包工具
String serverHost = "127.0.0.1"; //处事器IP
int serverPort = 10012; //处事器端标语
try{
//成立毗连
ds = new DatagramSocket();
//初始化
InetAddress address = InetAddress.getByName(serverHost);
byte[] b = new byte[1024];
receiveDp = new DatagramPacket(b,b.length);
System.out.println("客户端筹备完成");
//轮回30次,每次隔断0.01秒
for(int i = 0;i < 30;i++){
//初始化发送数据
Date d = new Date(); //当前时间
String content = d.toString(); //转换为字符串
byte[] data = content.getBytes();
//初始化发送包工具
sendDp = new DatagramPacket(data,data.length,address, serverPort);
//发送
ds.send(sendDp);
//延迟
Thread.sleep(10);
//吸收
ds.receive(receiveDp);
//读取反馈内容,并输出
byte[] response = receiveDp.getData();
int len = receiveDp.getLength();
String s = new String(response,0,len);
System.out.println("处事器端反馈为:" + s);
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
//封锁毗连
ds.close();
}catch(Exception e){}
}
}
}
在该示例中,将和处事器端举办数据互换的逻辑写在一个for轮回的内部,这样就可以实现和处事器端的多次互换了,思量随处事器端的响应速度,在每次发送之间插手0.01秒的时距离断。最后当数据互换完成今后封锁毗连,竣事措施。
实现该逻辑的处事器端措施代码如下:
package udp;
import java.net.*;
/**
* 可以并发处理惩罚数据包的处事器端
* 成果为:显示客户端发送的内容,并向客户端反馈字符串“OK”
*/
public class MulUDPServer {
public static void main(String[] args) {
DatagramSocket ds = null; //毗连工具
DatagramPacket receiveDp; //吸收数据包工具
final int PORT = 10012; //端口
byte[] b = new byte[1024];
receiveDp = new DatagramPacket(b,b.length);
try{
//成立毗连,监听端口
ds = new DatagramSocket(PORT);
System.out.println("处事器端已启动:");
while(true){
//吸收
ds.receive(receiveDp);
//启动线程处理惩罚数据包
new LogicThread(ds,receiveDp);
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
//封锁毗连
ds.close();
}catch(Exception e){}
}
}
}
#p#分页标题#e#
该代码实现了处事器端的吸收逻辑,利用一个轮回来吸收客户端发送过来的数据包,当吸收到数据包今后启动一个LogicThread线程处理惩罚该数据包。这样处事器端就可以实现同时处理惩罚多个数据包了。
实现逻辑处理惩罚的线程代码如下:
package udp;
import java.net.*;
/**
* 逻辑处理惩罚线程
*/
public class LogicThread extends Thread {
/**毗连工具*/
DatagramSocket ds;
/**吸收到的数据包*/
DatagramPacket dp;
public LogicThread(DatagramSocket ds,DatagramPacket dp){
this.ds = ds;
this.dp = dp;
start(); //启动线程
}
public void run(){
try{
//得到缓冲数组
byte[] data = dp.getData();
//得到有效数据长度
int len = dp.getLength();
//客户端IP
InetAddress clientAddress = dp.getAddress();
//客户端端口
int clientPort = dp.getPort();
//输出
System.out.println("客户端IP:" + clientAddress.getHostAddress());
System.out.println("客户端端标语:" + clientPort);
System.out.println("客户端发送内容:" + new String(data,0,len));
//反馈到客户端
byte[] b = "OK".getBytes();
DatagramPacket sendDp = new DatagramPacket(b,b.length,clientAddress,clientPort);
//发送
ds.send(sendDp);
}catch(Exception e){
e.printStackTrace();
}
}
}
在该线程中,只处理惩罚一次UDP通讯,当通讯竣事今后线程灭亡,在线程内部,每次得到客户端发送过来的信息,将得到的信息输出随处事器端措施的节制台,然后向客户端反馈字符串“OK”。
由于UDP数据传输进程中大概存在丢失,所以在运行该措施时大概会呈现措施阻塞的环境。假如需要制止该问题,可以将客户端的网络发送部门也修改成线程实现。
关于基本的UDP网络编程就先容这么多了,下面将先容一下网络协议的观念。