我试图在没有使用UDP的流量控制机制的情况下实现类似TCP的协议。所以我在Java中使用Datagram Socket。奇怪的是,当发送方使用大窗口大小,即在短时间内向接收方发送大量数据包时,接收方的数据报套接字会在一段时间后停止接收数据包。更明确地说,接收器程序停留在DatagramSocket.receive()
方法,似乎数据报套接字的接收缓冲区已溢出,并导致它在DatagramSocket.receive()
方法中阻塞。为了证实这种怀疑,我将接收缓冲区的大小设置得更大,然后麻烦就消失了。
所以我只想问一下当接收缓冲区溢出时会发生什么(除了丢弃数据包),以及为什么程序会在DatagramSocket.receive()
方法冻结并停止接收数据包。
public class Receiver {
String fileName; // output file name
short listeningPort;
InetAddress senderIp;
short senderPort;
String logFileName; // the log file name
DatagramSocket inSocket; // udp socket to receive data
Socket outSocket; // tcp socket to send control message
PriorityQueue<Packet> outOfOrder; // buff to save the out of order packet
DataOutputStream send;
FileOutputStream wFile;
PrintWriter wLog;
private int receiverSeqN = 0;// the sequence number for sending packet to sender
private int receiverAckN = 0; // the ack sequence number
private boolean receiverFIN = false;
public Receiver( String fN, short lP, String sI, short sP, String lFN){
fileName = fN;
listeningPort = lP;
senderPort = sP;
logFileName = lFN;
outOfOrder = new PriorityQueue<Packet>();
try {
senderIp = InetAddress.getByName(sI);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
outSocket = new Socket(senderIp,senderPort); // create the TCP socket to send control message to sender
send = new DataOutputStream(outSocket.getOutputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
inSocket = new DatagramSocket(lP); // create the UDP socket to listen
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
wFile = new FileOutputStream(fileName);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("unable to creat file.");
e.printStackTrace();
}
try {
wLog = new PrintWriter(logFileName);
} catch (FileNotFoundException e) {
System.out.println("unable to creat log file");
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// receiving packet
public void receive(){
byte[] buff = new byte[1024];
DatagramPacket dp = new DatagramPacket(buff,0,buff.length);
try {
inSocket.receive(dp); // *program stuff here!!!!*
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] data = Arrays.copyOf(dp.getData(), dp.getLength());
Packet newPak = new Packet(Timestamp.from(Instant.now()),data);
log(newPak);
if (newPak.corrupted || outOfOrder.contains(newPak) || newPak.seqN < receiverAckN) {
sendAck(receiverAckN);
return;
}
outOfOrder.add(newPak);
Packet current = outOfOrder.peek();
while (current.seqN == receiverAckN){
if ( current.FIN ) receiverFIN = true;
receiverAckN++;
deliver(current.message);
outOfOrder.poll();
if(outOfOrder.isEmpty()) break;
current = outOfOrder.peek();
}
sendAck(receiverAckN);
}
// send the ack packet to the sender
public void sendAck(int ackN){
Packet pak = new Packet(Timestamp.from(Instant.now()),listeningPort, senderPort, receiverSeqN++, ackN, true,receiverFIN, new byte[0]);
log(pak);
try {
send.write(pak.toByteArray());
send.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// deliver message to the file
public void deliver(byte[] message){
byte[] temp = Arrays.copyOf(message, message.length);
try {
// System.out.println(new String(temp, 0, temp.length));
wFile.write(temp );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// log the packet
public void log(Packet packet){
wLog.write(packet.toString());
wLog.write("\n");
wLog.flush();
}
// receiving message
public void go(){
while(!receiverFIN){
receive();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
try {
wFile.flush();
wLog.flush();
wFile.close();
wLog.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
send.close();
inSocket.close();
outSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("The reception is successful.");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Receiver receiver = new Receiver(args[0], Short.parseShort(args[1]), args[2], Short.parseShort(args[3]),args[4]);
receiver.go();
}
}