📄 simplegobacknagent.java
字号:
return;
}
// Create a properly filled out packet
SimpleGoBackNPacket packet = new SimpleGoBackNPacket();
// Todo: set sequence numbers+acks properly
packet.source_port = m_local_port;
packet.destination_port = m_local_port;
packet.sequence = m_seq_data++;
packet.ack = 0;
packet.flags = 0;
packet.length = SimpleGoBackNPacket.HEADER_SIZE + length;
packet.data = data;
// Put the packet in the send queue
m_send_array.addElement(packet);
// m_sgn.send(m_local_ip,m_remote_ip,length,packet,m_local_port);
Simulator.getInstance().schedule(new SGNUpdateCommand(
Simulator.getInstance().getTime() + 0.0001, this));
}
public Object read(int unique_id)
{
return null;
}
/**
This is an agent that serves the application layer. We will thus always
allow packets to be sent for convenience and buffer them ourselves.
@param destination ignored
@param length ignored
@return true
*/
public boolean canSend(IPAddr destination, int length)
{
return true;
}
/**
Indicate an event to this agent.
@see jns.agent.Agent
*/
public void indicate(int status, Object indicator)
{
if(status == Agent.READY_TO_SEND)
{
// System.out.println(" SGN RTS");
if(m_send_array.size() > 0 && m_window_pos < m_window_size &&
m_window_pos < m_send_array.size())
{
Simulator.getInstance().schedule(new SGNUpdateCommand(
Simulator.getInstance().getTime() + 0.0001, this));
}
}
else if(status == Agent.PACKET_AVAILABLE)
{
// Get a packet from the multiplexer
IPPacket ippacket = (IPPacket) m_sgn.read(m_local_port);
SimpleGoBackNPacket packet = (SimpleGoBackNPacket) ippacket.data;
// Treat the packet according to the current state. Note that it is
// not a terribly good use of ones time to try to understand this
// piece of code without having the chart of the tcp finite state
// machine within sight.
switch(m_state)
{
case CLOSED:
Simulator.warning("SGN received a packet in the closed" +
" state. Ignored.");
break;
case LISTEN:
if(packet.flags == SimpleGoBackNPacket.SYN)
{
// Extract the port & IP of the sender
m_remote_port = packet.source_port;
m_remote_ip = ippacket.source;
Simulator.verbose(" SGN got SYN in listen");
sendPacket(SimpleGoBackNPacket.SYN |
SimpleGoBackNPacket.ACK,
m_seq_data, packet.sequence);
m_state = SYN_RECVD;
}
break;
case SYN_SENT:
if(packet.flags == SimpleGoBackNPacket.SYN)
{
sendPacket(SimpleGoBackNPacket.SYN |
SimpleGoBackNPacket.ACK, m_seq_data,
packet.sequence);
m_state = SYN_RECVD;
}
else if(packet.flags == (SimpleGoBackNPacket.SYN |
SimpleGoBackNPacket.ACK))
{
sendPacket(SimpleGoBackNPacket.ACK, m_seq_data,
packet.sequence);
m_state = ESTABLISHED;
m_user.indicate(Agent.CONNECTION_ESTABLISHED, this);
Simulator.verbose(" SGN connection established");
}
break;
case SYN_RECVD:
if(packet.flags == SimpleGoBackNPacket.ACK)
{
m_state = ESTABLISHED;
m_user.indicate(Agent.CONNECTION_ESTABLISHED, this);
Simulator.verbose(" SGN connection established");
}
break;
case ESTABLISHED:
// If it's a FIN packet, send an ACK and go to the next
// state.
if(packet.flags == SimpleGoBackNPacket.FIN)
{
sendPacket(SimpleGoBackNPacket.ACK, m_seq_data, 0);
m_state = CLOSE_WAIT;
}
// If it's an ACK for a packet we sent, move the window
if(packet.flags == SimpleGoBackNPacket.ACK &&
m_send_array.size() > 0)
{
if(packet.ack == ((SimpleGoBackNPacket)
m_send_array.elementAt(0)).sequence)
{
m_send_array.removeElementAt(0);
if(m_window_pos > 0)
m_window_pos--;
}
}
// Otherwise we just received some data. Send back an
// ACK and stick it in the receive queue
if(packet.data != null)
{
sendPacket(SimpleGoBackNPacket.ACK, m_seq_data,
packet.sequence);
m_recv_array.addElement(packet);
}
break;
case CLOSE_WAIT:
sendPacket(SimpleGoBackNPacket.FIN, m_seq_data, 0);
m_state = LAST_ACK;
break;
case LAST_ACK:
if(packet.flags == SimpleGoBackNPacket.ACK)
m_state = CLOSED;
break;
case FIN_WAIT1:
if(packet.flags == SimpleGoBackNPacket.FIN)
{
sendPacket(SimpleGoBackNPacket.ACK, m_seq_data,
packet.sequence);
m_state = CLOSING;
}
else if(packet.flags == SimpleGoBackNPacket.ACK)
{
m_state = FIN_WAIT2;
}
else if(packet.flags == (SimpleGoBackNPacket.FIN |
SimpleGoBackNPacket.ACK))
{
sendPacket(SimpleGoBackNPacket.ACK, m_seq_data,
packet.sequence);
m_state = TIME_WAIT;
}
break;
case FIN_WAIT2:
if(packet.flags == SimpleGoBackNPacket.FIN)
m_state = TIME_WAIT;
break;
case CLOSING:
if(packet.flags == SimpleGoBackNPacket.ACK)
m_state = TIME_WAIT;
break;
}
}
}
/**
Internal function to which calls are scheduled with the simulator.
On each call, update will try to send a packet (if the window size
and ACKs permit it)
*/
protected void update()
{
if(m_send_array.size() > 0 && m_window_pos < m_window_size &&
m_window_pos < m_send_array.size())
{
SimpleGoBackNPacket packet =
(SimpleGoBackNPacket) m_send_array.elementAt(m_window_pos);
m_sgn.send(m_local_ip, m_remote_ip, packet.length, packet, m_local_port);
m_window_pos++;
}
}
// ------------- Convenience functions to make life easy -----------
/**
sendPacket is used to send control packets (SYN, etc.). Those packets
contain no data.
*/
private void sendPacket(int flags, int seq, int ack)
{
// Create a properly filled out packet
SimpleGoBackNPacket packet = new SimpleGoBackNPacket();
// Todo: set sequence numbers+acks properly
packet.source_port = m_local_port;
packet.destination_port = m_remote_port;
packet.sequence = seq;
packet.ack = ack;
packet.flags = flags;
packet.length = SimpleGoBackNPacket.HEADER_SIZE;
packet.data = null;
// Send the packet
m_sgn.send(m_local_ip, m_remote_ip, packet.length, packet, m_local_port);
}
}
/**
A command class that will simply call the update() function of the
SimpleGoBackNAgent at a specific time.
*/
class SGNUpdateCommand extends Command
{
SimpleGoBackNAgent m_agent;
public SGNUpdateCommand(double time, SimpleGoBackNAgent agent)
{
super("SGN update", time);
m_agent = agent;
}
public void execute()
{
m_agent.update();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -