}sumRtt+=rtt[i];},通过循环获取极值。
五.关键性的代码
1.客户端发送请求和接收回复
DatagramSocketclientSocket=newDatagramSocket();//生成client端socket实例
InetAddressIPAddress=InetAddress.getByName(address);//生成ip地址实例
byte[]sendData=newbyte[1024];//用于接收数据的byte数组
byte[]receiveData=newbyte[1024];//用于发送数据的byte数组
sendData=sentence.getBytes();
DatagramPacketsendPacket=newDatagramPacket(sendData,sendData.length,IPAddress,port);//生成发送数据包
DatesendBefore=newDate();//发送前时
clientSocket.send(sendPacket);//发送
DatagramPacketreceivePacket=newDatagramPacket(receiveData,receiveData.length);//生成接收数据包
clientSocket.receive(receivePacket);//接收从server返回的数据包
DatereceiveAfter=newDate();//接收后的时间
//最多等待1秒以便接收PingServer返回的reply消息。
如果在该时间内没有收到服务器的reply,则认为该请求或对该请求的reply已经丢失
StringmodifiedSentence="";
if(receiveAfter.getTime()-sendBefore.getTime()>1000){
modifiedSentence="请求超过1秒,模拟数据丢失!
!
\n";
rtt[i-1]=(long)0;//当收不到reply时,置折返时间为0,不加入计算
}else{modifiedSentence=newString(receivePacket.getData());
rtt[i-1]=receiveAfter.getTime()-sendBefore.getTime();
}
2.服务器端接收请求和回复客户端
newThread(){@Override
publicvoidrun(){
intcilentCount=0;//客户端的数量(多个客户端)
//服务器端一直处于接收状态
while(true){
byte[]sendData=newbyte[1024];
DatagramPacketreceivePacket=newDatagramPacket(receiveData,receiveData.length);//生成接收数据报包实例
try{serverSocket.receive(receivePacket);}catch(Exceptione){e.printStackTrace();}//从客户端接收到请求
Stringsentence=newString(receivePacket.getData());
InetAddressIPAddress=receivePacket.getAddress();//获得client端的ip
intport=receivePacket.getPort();//获得client端的port
longrandomTime=(long)(Math.random()*1000);//生成随机数,用于模拟传输延迟
try{Thread.sleep(randomTime);}catch(InterruptedExceptione){e.printStackTrace();}//程度睡眠,用于模拟传输延迟
if(sentence.substring(7,8).equals("1")&&!
sentence.substring(7,9).equals("10")){
cilentCount++;System.out.println("***********************************************");
System.out.println("*第"+cilentCount+"台客户端机正在请求!
!
!
!
!
*");
System.out.println("***********************************************\n");
}System.out.println("从客户端接收到的信息为:
");
System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
System.out.println(sentence);sendData=sentence.getBytes();
DatagramPacketsendPacket=newDatagramPacket(sendData,sendData.length,IPAddress,port);//生成数据包
try{serverSocket.send(sendPacket);}catch(Exceptione){e.printStackTrace();}//发回client端}
}.start();
六.开发过程中遇到的问题及解决办法
1.问题:
在编写程序的过程中,因为对socket编程不了解,导致不能正确让客户端和服务器端相互发送消息。
解决:
网上查询socket相关的编程知识,调用javaJDK中包下的DatagramSocket和DatagramPacket类,实现客户端和服务器端的信息交流。
2.问题:
刚开始编程时,服务器端不能服务多个客户端。
解决:
通过多线程编程,使不同客户端的请求运行在不同的线程,来实现服务器端对多个客户端的请求服务。
七.程序中待解决的问题及改进方向
1.待解决的问题:
程序界面不过人性化。
改进方向:
继续深入优化
八.程序测试结果
客户端请求
服务器端回复
以下为完整代码
客户端代码
importjava.io.BufferedReader;
importjava.io.InputStreamReader;
importjava.io.StringReader;
import.DatagramPacket;
import.DatagramSocket;
import.InetAddress;
importjava.text.SimpleDateFormat;
importjava.util.Date;
/*PingClient,客户端,有以下功能
3.1启动后发送10个request。
发送一个request后,最多等待1秒以便接收PingServer返回的reply消息。
如果在该时间内没有收到服务器的reply,则认为该请求或对该请求的reply已经丢失;在收到reply后立即发送下一个request。
3.2请求消息的payload中至少包含关键字PingUDP、序号、时间戳等内容。
如:
PingUDPSequenceNumberTimeStampCRLF
其中:
CRLF表示回车换行符(0X0D0A);TimeStamp为发送该消息的机器时间。
3.3为每个请求计算折返时间(RTT),统计10个请求的平均RTT、最大/小RTT。
3.4通过如下命令行启动:
javaPingClienthostport。
host为PingServer所在的主机地址;port为PingServer的工作端口号
*/
publicclassPingClient
{
publicstaticvoidmain(String[]args)throwsException
{
Stringaddress=args[0];//从命令行获得serverip地址
intport=newInteger(args[1]);//从命令行获得端口号
long[]rtt=newlong[10];//用于折返时间的统计
System.out.println("\n客户端启动,开始发送请求!
!
!
!
\n\n\n");
for(inti=1;i<=10;i++)//发送10条请求
{
SimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-ddhh:
mm:
ss.SS");//时间戳格式
Stringsentence="头部:
请求"+i+"\n"//请求数据
+"payload:
PingUDP序号:
"+i+"时间戳:
"
+sdf.format(newDate())+"\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
DatagramSocketclientSocket=newDatagramSocket();//生成client端socket实例
InetAddressIPAddress=InetAddress.getByName(address);//生成ip地址实例
byte[]sendData=newbyte[1024];//用于接收数据的byte数组
byte[]receiveData=newbyte[1024];//用于发送数据的byte数组
sendData=sentence.getBytes();
DatagramPacketsendPacket=newDatagramPacket(sendData,sendData.length,IPAddress,port);//生成发送数据包
DatesendBefore=newDate();//发送前时间
clientSocket.send(sendPacket);//发送
DatagramPacketreceivePacket=newDatagramPacket(receiveData,receiveData.length);//生成接收数据包
clientSocket.receive(receivePacket);//接收从server返回的数据包
DatereceiveAfter=newDate();//接收后的时间
//最多等待1秒以便接收PingServer返回的reply消息。
如果在该时间内没有收到服务器的reply,则认为该请求或对该请求的reply已经丢失
StringmodifiedSentence="";
if(receiveAfter.getTime()-sendBefore.getTime()>1000){
modifiedSentence="请求"+i+"超过1秒,模拟数据丢失!
!
";
rtt[i-1]=(long)0;//当收不到reply时,置折返时间为0,不加入计算
}else{
modifiedSentence=newString(receivePacket.getData());
rtt[i-1]=receiveAfter.getTime()-sendBefore.getTime();
}
System.out.println("折返时间和服务端的返回信息为:
");
System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
System.out.println("折返时间(RTT):
"+rtt[i-1]);
System.out.println(modifiedSentence);//显示从server返回的数据
if(rtt[i-1]==0){
System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n\n\n\n\n\n");
}
clientSocket.close();//关闭socket
}
//统计出平均rtt,最大rtt和最小rtt
longsumRtt=0;
longmaxRtt=0;
longk=0;
longminRtt=rtt[0];
intj=0;
for(inti=0;i<10;i++)
{
if(rtt[i]>k){
if(rtt[i]>maxRtt)
{
maxRtt=rtt[i];
}
if(rtt[i]{
minRtt=rtt[i];
}
j++;
sumRtt+=rtt[i];}
}
System.out.println("最终折返时间为:
");
System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
System.out.println("平均折返时间:
"+sumRtt/j+"ms");
System.out.println("最大折返时间:
"+maxRtt+"ms");
System.out.println("最小折返时间:
"+minRtt+"ms");
System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
}
}
服务端代码
importjava.io.BufferedReader;
importjava.io.InputStreamReader;
import.DatagramPacket;
import.DatagramSocket;
import.InetAddress;
/**
*PingServer服务器端,完成以下功能
*2.1可以并发地为多个用户服务;
2.2显示用户通过客户端发送来的消息内容(包含头部和payload);
2.3能够模拟分组的丢失;能够模拟分组传输延迟;
2.4将用户发送来的请求request在延迟一段随机选择的时间(小于1s)后返回给客户端,作为收到请求的响应reply;
2.5通过如下命令行启动服务器:
javaPingServerport。
port为PingServer的工作端口号
*/
publicclassPingServer
{
publicstaticvoidmain(String[]args)throwsException
{
System.out.println("\n服务端启动,等待客户端请求.......\n\n\n");
intinitPort=newInteger(args[0]);//从命令行获得portargs[0]
DatagramSocketserverSocket=newDatagramSocket(initPort);//根据port,生成server端socket实例
byte[]receiveData=newbyte[1024];
/*
*使用多线程编程,可以实现多个客户端同时请求服务端
*/
newThread(){
@Override
publicvoidrun(){
intcilentCount=0;//客户端的数量(多个客户端)
//服务器端一直处于接收状态
while(true)
{
byte[]sendData=newbyte[1024];
DatagramPacketreceivePacket=newDatagramPacket(receiveData,receiveData.length);//生成接收数据报包实例
try{serverSocket.receive(receivePacket);}catch(Exceptione){e.printStackTrace();}//从客户端接收到请求
Strin