Serializing classes across a network socket (TCP/IP)






4.64/5 (9 votes)
This article gives example and code for sending a class across a network connection using TCP/IP and the CBlockingSocket class.
Introduction
This article shows you how to serialize a class or standard variable over a TCP/IP socket connection. It shows an example of how to setup the TCP/IP connection, setup other needed classes, and send/receive data over the socket.
I pulled from the MFC class CSocketFile
. As you may know, CSocketFile
lets you send and receive data to/from a network connection using a CArchive
. The drawback is that the implementation of CSocket
that is used has 16 bit code in it - not good for any decent application.
So I basically re-wrote them using CBlockingSocket
(instead of CSocket
) which uses 32 bit code and is better optimized. This allows you to attach a CArchive
to an open CSocketFile
and then serialize data to and from it (thus sending an receiving the data across the network).
Details
Here are the basic steps:
- Create and connect a
CBlockingSocket
object to the computer you want to send/receive data with - Create a
CBlockingSocketFile
and attach it to theCBlockingSocket
object you created in step 1 above. - Create a
CArchive
object and attach it to theCBlockingSocketFile
object you created in step 2 above.
NOTE: You must create 1CArchive
for sending and 1 for receiving. - Send your data or classes using the
CArchive
object created in step 3. You can send any serializable class or raw variables.
VERY IMPORTANT NOTE: make sure you flush theCArchive
object after you’re done sending data. This ensures all data is written across the network and tells the socket at the other end to go ahead and receive it. - Close out the
CArchive
objects and theCBlockingSocket
object. NOTE: Don’t close theCBlockingSocketFile
object or it will assert.
Example code
// Step 1: Create CBlockingSocket and connect CSockAddr sockAddr("127.0.0.1", SERVER_PORT); CBlockingSocket socket; socket.Create(); socket.Connect(LPSOCKADDR(sockAddr)); // Step 2: Create socket file and attach CBlockingSocketFile sockFile(&socket); // Step 3: Create CArchive and attach CArchive arSend(&sockFile, CArchive::store ); // use store to send data CArchive arRecv(&sockFile, CArchive::load); // use load to receive data // Step 4: Send the data using the archive unsigned int uiCommand = 9; CString strText("Some text to send"); arSend << uiCommand; arSend.Flush(); strText.Serialize(arSend); arSend.Flush(); // Step 4 (optional): Receive response strText.Serialize(arRecv); // (optional) Display received text MessageBox(LPCTSTR(strText), "Response from socket", MB_OK); // Step 5: Close up connection arSend.Close(); arRecv.Close(); socket.Close();
Conclusion
That’s basically it. Of course, I’m making one assumption that there’s a listening socket on the other end ready to send/receive the data. For convenience I’ve added an appendix below with the code to setup a listening (server) socket and receive the data then send an acknowledgment.
In the future I may derive from CArchive
and add functionality to make this whole process even easier, but for now I think this is pretty straight forward. Enjoy and happy coding!
Appendix A – Setup a listening (server) socket
// TCP/IP variables CBlockingSocket listenSocket; CSockAddr saServer; CBlockingSocket clientSocket; // socket that is connected // to the client for communication. CSockAddr clientSA; // client socket address class UINT uiCommand; // command received from TCP CString strText; // for receiving / sending over socket connection // TCP/IP - Initialize the listening socket try{ // socket initialization CSockAddr saServer(INADDR_ANY, SERVER_PORT); listenSocket.Create(); listenSocket.Bind(saServer); listenSocket.Listen(); }catch(CBlockingSocketException *e) { listenSocket.Cleanup(); // cleanup socket (this won't throw an exception) return; } // Accept will block until an incoming client connection is // received. You can put this in a loop or // spawn child threads to handle multiple client request if(!listenSocket.Accept(clientSocket, clientSA)){ // Accept failed, log the failure DEBUG_LOG2("CScheduler::run(): Accept failed with code: ", WSAGetLastError()); } // Receive the incoming data // Create & attach a CBlockingSocketFile CBlockingSocketFile sockFile(&clientSocket); // Create/attach a CArchive for sending / receiving CArchive arSend(&sockFile, CArchive::store); CArchive arRecv(&sockFile, CArchive::load); // Receive integer arRecv >> uiCommand; // Receive CString data strText.Serialize(arRecv); // Send acknowledgment strText = “Integer and text received”; strText.Serialize(arSend); arSend.Flush(); // very important to flush all sent data // close connection arSend.Close(); arRecv.Close(); // Close receiving client socket (don't close socket file // or else exception will be thrown) clientSocket.Close();