Biasanya dalam permainan komputer FPS, protokol UDP digunakan untuk menghantar lokasi dan aksi si pemain. Data-data ini akan dihantar berterusan kepada pemain lain. Namun, apabila data yang dihantar tidak sampai, ia akan dibiarkan tanpa dihantar semula agar permainan itu tidak kelihatan lewat atau lambat. Lain pula apabila menghantar fail, protokol baru perlu dibina diatas UDP bagi memastikan data yang dihantar lengkap dan mencukupi.
Tentang Projek Ini
Ini adalah satu projek ringkas untuk menunjukkan penghantaran fail melalui UDP. Kemungkinan kod-kod yang dipaparkan disini mempunyai ralat dan mungkin tidak dapat untuk menghantar fail dengan sempurna.
Download Fail Projek + Demo
UDP
Bagi memulakan projek ini, satu kelas ringkas bagi soket UDP perlu dihasilkan. Kelas ini dinamakan CSockUDP dan mempunyai method-method berikut:
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();
}
Metod InitWinsock() dan DestroyWinsock() adalah panggilan ke WinsockAPI untuk memulakan penggunaan Winsock DLL dan menghentikannya. Ia perlu dipanggil awal semasa program baru berjalan dan juga sebelum program berakhir.
Panggilan kepada CreateSocket() akan membuat satu soket UDP dengan port yang ditetapkan. Selepas itu, metod SetCallback() perlu dipanggil untuk penerimaan data. StartListen() akan membina satu bebenang baru bagi melaksanakan satu fungsi gelung untuk memeriksa jika ada data masuk. Metod-metod yang lain jelas maksudnya dan rasanya tidak memerlukan penerangan.
----
Untuk menghantar fail melalui UDP, pertama sekali protokol untuk penghantaran fail perlu dibina. Setiap data yang dihantar mestilah mempunyai pengenalan supaya penerima faham apakah yang baru diterimanya itu dan apa yang perlu dibuat pada data yang baru diterimanya itu. Untuk itu kita akan membuat satu struktur bagi data header dengan disusuli oleh data yang hendak dihantar.
struct TUDPHeader { char szID[3]; // 'IKH' - unique id DWORD dwCRC32; // Checksum of Data char type; // eDataType int nLength; // Data length // Data (TUDPFileHeader/TUDPFileReply/TUDPFileTransfer) };Didalam header ini ada satu pengenalan, szID yang akan mempunyai data "IKH" untuk pengenalan kepada penerima. Jika paket yang diterimanya lain daripada "IKH" tadi, paket data tersebut akan terus diabaikan tanpa dibaca kerana kemungkinan ianya datang daripada software yang lain.
dwCRC32 akan diisi dengan checksum bagi keseluruhan data (tidak termasuk TUDPHeader). Penghantar akan mengira checksum bagi data-data yang akan dihantar dan dimasukkan kedalam dwCRC32. Penerima, setelah menerima paket akan mengira semula checksum bagi data dan membandingkan dengan dwCRC32 yang dihantar. Jika terdapat perbezaan, kemungkinan data yang dihantar korup atau rosak ataupun telah diubah. Penerima akan meminta data tersebut dihantar semula.
type fungsinya menjelaskan kepada penerima jenis data apakah yang dihantar.
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 };
Kemudian, akhir sekali pada Header adalah nLength, yang akan memberitahu penerima berapa besar saiz data yang dihantar agar penerima tahu dimanakah data tersebut tamat.
----
Sewaktu fail hendak dihantar, satu paket data akan dibina menggunakan TUDPHeader diikuti dengan TUDPFileHeader. Ia akan menghantar nama fail diikuti dengan panjang fail tersebut dalam unit bytes.
struct TUDPFileHeader { char szFileName[128]; int nFileSize; };
Setelah itu, penerima akan membalas sama ada untuk menerimanya atau tidak seperti yang boleh dilihat di eDataType, eDataTypeFileReplyAccept/eDataTypeFileReplyReject. Jika diterima, penerima akan membina satu fail dan penghantar akan terus menghantar fail tersebut menggunakan TUDPFileTransfer yang mengandungi offset, saiz data, dan data fail itu sendiri.
struct TUDPFileTransfer { int nFileOffset; int nLength; char szData[2048]; };
Penerima pula akan menulis fail yang dibinanya tadi dengan data yang dibekalkan sehingga lengkap.
Contoh menghantar TUDPHeader + TUDPFileHeader |
No comments:
Post a Comment