I ended up writing all of the data recved to a buffer, like you suggested. But instead of then sweeping the buffer for control "packet boundary" characters, I do the following:
I have a boolean variable that reflects whether or not my program is in "mid packet." If it is not mid-packet, I read a single byte, the ID of what kind of packet is being sent, and set midpacket to true. Then, from that single byte received, I look up the size of that kind of packet and call it totalPacketSize.
Every time select notifies my program that the socket has incoming data waiting, I call recv again, with totalPacketSize - lengthOfDataAlreadyRead as the requested number of bytes to read. I add however many bytes are received to lengthOfDataAlreadyRead (actually called dataLen), and repeat the process until dataLen equals totalPacketSize, so I know that the whole packet has been received. Then I copy the buffer to the appropriate packet structure (I actually have a bunch unioned into one generic PACKET). Then I set midpacket to false again, and dataLen to 0, and the process can start over for the next packet.
PACKET packet; int bytesReceived; if (!midPacket) { midPacket = true; //we just want to read a single byte, the id of the packet, and then figure out wth to do with the rest bytesReceived = socket.recv((char *)buffer, 1, 0); if (bytesReceived == 1) //this will always be true but whatever { totalPacketSize = getPacketSize(buffer[0]); //remember buffer[0] now holds the packet ID if (totalPacketSize == -1) cout << "ERROR: Invalid packet type sent!!" << endl << flush; dataLen = 1; } } bytesReceived = socket.recv((char *)buffer + dataLen, totalPacketSize - dataLen, 0); dataLen += bytesReceived; if (bytesReceived == 0) { cout << socket.ip << " disconnected :(\n" << flush; socket.disconnect(); active = false; //deactivate myself return; } if (dataLen >= totalPacketSize) //if we've gotten the whole packet { //copy the buffer to the packet memcpy(&packet, buffer, dataLen); midPacket = false; switch(packet.id) //decide how to interpret the data: { case PID_LOGON: cout << "User " << packet.logon.username << " has logged on.\n" << flush; break; //and etc...
This seems like it shoudl work fine for me. The only problem would be if packets could come partially, which is something that I still don't know about - can the first part of a packet come and then the start of another before the end of the first packet?
Thanks
-riley
Edited by - rileyriley on October 23, 2001 3:23:53 PM