Archived

This topic is now archived and is closed to further replies.

vaceX

A couple of questions regarding udp & packets.

Recommended Posts

vaceX    122
1)What things are important to include when building a packet? Packet-length? Checksum? Some sort of timestamp? Some sort of packet-id? 2)Theoretically, how does guaranteed packet shipping work in UDP? Maybe someone can give me an example of how a packet could be built (exactly)?

Share this post


Link to post
Share on other sites
cbenoi1    484
quote:
Original post by vaceX
Maybe someone can give me an example of how a packet could be built (exactly)?


AirHook, an implementation of a TCP-like layer atop UDP. Source code included.

-cb

Share this post


Link to post
Share on other sites
fingh    142
Assuming a single packet is sent with a single call to sendto(), you can use a very simple header like so:

      
struct packet_header
{
short packet_type;
short packet_sequence;
long last_sent;
};

class packet : public packet_header
{
...
};

func_send(data, type)
{
if (type == FULLY_RELIABLE)
{
packet = new packet(data, type, next_reliable_sequence++, current_time);

queue_outgoing(packet, packet.packet_sequence);
}
else
{
packet = new packet(data, type, next_ordered_sequence++, current_time);

}
send(packet);
}

func_resend()
{
for( each packet in outgoing_queue)
{
if (packet->last_sent > rtransmission_timer)
{
packet->last_sent = current_time;
send(packet);
}
}
}

func_recv()
{
for(some interval of time)
{
int packet_size = recvfrom(buffer, recvfrom_addr);
if (recvfrom_addr is new)
{
add_new_connection(recvfrom_addr);
}
struct packet_header *hdr = buffer;
switch(hdr.packet_type)
{
case INORDER:
if (hdr.packet_sequence < last_received_packet_sequence)
{
break;
}
process_packet(buffer);
break;
case FULLY_RELIABLE:
queue_packet(recvfrom_addr, buffer, hdr.packet_sequence);
ack_packet(hdr.packet_sequence);
break;
} // switch

}// for timeout

}

process_connection(addr)
{
queue packet;
for(each packet in queue)
{
if (packet->packet_sequence == current_packet)
{
process_packet();
}
else
{
// ignore packets until the correct packet arrives

break;
}
if (time > sometimeout)
{
break;
}
}

}

main()
{
list addr;
for (ever)
{
// call send only when needed of course

if(data_to_send)
{
func_send(...);
}

// check for incoming

func_recv();

// process each virtual connection

for(each addr in list)
{
process_connection(addr);
}
}
}


As I said, psudeo-code, but the general idea is illustrated. AirHook goes to the extreme of reinventing the TCP wheel, but in general that isn't necessary to get improved performance over other methods of transport.

Basic description of the code goes like this:
You have a list of addresses representing current 'virtual' connections. If you receive from a new addr, then add it to the list. If you send reliable data, queue it and keep a time stamp. If no ack is received from the peer after some timeout, resend it. When an ack is received, delete the packet from your queue. When you receive a guaranteed packet, process it only if it's the next packet in sequence. Otherwise move on to process other connections until the timeout expires (or there is no more data)


[edited by - fingh on March 5, 2003 3:33:49 PM]

Share this post


Link to post
Share on other sites
Anon Mike    1098
What exactly are you asking?

UDP already has a packet length that is set automatically. On the recieving end you can only receive whole packets.

UDP (IP) also has a built-in checksum. It may or may not be good enough for you.

Whether or not a timestamp is useful depends on exactly what your application is.

Most protocols need some way of saying what data is in the packet. A few don''t.

There is no such thing as guaranteed packet shipping in UDP. You can build a protocol that does that sort of thing which is what the people above are talking about but it''s not built-in.

Share this post


Link to post
Share on other sites