Introduction
Normally in a realtime game such as FPS, UDP protocol is used to send player location and behaviour. This data will be send continuously to provide a realtime player action to other player. But when the data is not arrived, the data will be skipped without retransmission so that the gameplay will be realtime, and not delayed. When sending files, a new protocol must be constructed as the file data must be sent completely. It cannot be skipped as it will corrupt the file.
About This Project
This is a simple project to demonstrate sending a file through UDP Socket. The code here might not perfect and may contains several flaws and bugs which might prevent the file from being sent perfectly.
Download Project file + Demo
UDP
To start this project, a simple UDP socket class must be constructed to assists sending and receiving data packet through UDP socket. This class will be named CSockUDP and will contain this method:
class CSockUDP
{
public:
static int InitWinsock();
static void DestroyWinsock();
void SetCallback(cbDataRecieved fnRecieved);
int CreateSocket(int nPort = 31313);
void StartListen();
void StopListen();
bool SetServerAddress(char* szServer, int nPort);
int SendData(LPVOID lpData, int nSize);
int ResendData();
}
InitWinsock() and DestroyWinsock() is a call to WinsockAPI to initiates and stop the use of Winsock Dll. It must be called on very early when the program is started and on the very end before the program terminated.
A call to CreateSocket() will create a new UDP socket and assign it with a port number. Then, SetCallback() is called to set receive event function. StartListen() will create a new thread which will executes a loop code and listen for any incoming data. Other method is self explanation.
----
To send files through UDP socket, firstly a protocol must be constructed. Every data packet that is sent must have some sort of acknowledgement and identification so the receiver can understand what is it and what should it do. We can start by creating a data header followed by the data itself.
struct TUDPHeader { char szID[3]; // 'IKH' - unique id DWORD dwCRC32; // Checksum of Data char type; // eDataType int nLength; // Data length // Data (TUDPFileHeader/TUDPFileReply/TUDPFileTransfer) };Inside this header, szID is an identification. It will contain unique data, "IKH" in this case and send it to the receiver. When the receiver read the data and found that the first 3 bytes is equal to "IKH", it will continue read the packet but when it different, the packet will simply be skipped as it might come from other software that is also sending a data to the same port.
dwCRC32 will contain a data checksum (not including TUDPHeader). The sender will calculate the data checksum and fill dwCRC32 with it. When it arrives at destination, the receiver will calculate the data checksum again and compare it with dwCRC32. If the checksum calculated by receiver differ from what is sent by sender, it will indicates that the data is corrupted or altered before its reach its destination. If this happen, the receiver will request that the data must be sent back again.
type explains to the receiver what must it do with the data.
enum eDataType { eDataTypeConnect, // ping eDataTypeConnected, // Reply if server got connect message eDataTypeResend, // Corrupted data, request for resend eDataTypeQuit, // Exit the program, client and server eDataTypeFileHeader, // TUDPFileHeader eDataTypeFileTransfer, // TUDPFileTransfer eDataTypeFileReplyAccept, // Accept the file send request eDataTypeFileReplyReject, // Denied the file send request eDataTypeFileReplyOK, // Proceed to next stream eDataTypeFileReplyFinish // Finished transfer };
Lastly inside this header (TUDPHeader), is nLength. nLength will tell how big is the data sent by sender. Without it, the receiver does not know when the data end.
----
When a file is being sent, a packet is constructed from TUDPHeader followed by TUDPFileHeader. It will send a file name followed by size of the file in bytes.
struct TUDPFileHeader { char szFileName[128]; int nFileSize; };
After that, receiver will reply either to accept the file or reject it like we can see in eDataType, eDataTypeFileReplyAccept/eDataTypeFileReplyReject. If the file is accepted, the receiver will create a new file and the sender will immediately send the file data using TUDPFileTransfer which contain file offset, data size and the file data itself.
struct TUDPFileTransfer { int nFileOffset; int nLength; char szData[2048]; };
The receiver then writes the newly created file with the data its received in TUDPFileTransfer until the file completed.
Example of sending data packet with TUDPHeader + TUDPFileHeader |
No comments:
Post a Comment