Click here to Skip to main content
14,920,539 members
Please Sign up or sign in to vote.
4.67/5 (3 votes)
See more:
Hello All,

I am using sockets API to communicate to a printer.
I need to receive the data sent from the printer to my application.
The data is a binary image attachment packaged as a MIME Multipart-Related content type.
I am using the recv() function like this:
C++
// Receive until the peer closes the connection
do 
{

    iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
    if ( iResult > 0 )
    {
        // To Do: Maybe add a fucntion here to save the data to another
        // buffer which is dynamically adjusting in length to be able to hold
        // the total bytes received.
        printf("Bytes received: %d\n", iResult);
    }
    else if ( iResult == 0 )
    {
        printf("Connection closed\n");
    }
    else
    {
        printf("recv failed: %d\", WSAGetLastError());
    }

}while( iResult > 0 );

My problem is the size of data to be received is unpredictable and quite large.
I trying to create another buffer that will be dynamically allocated (by using realloc()) whenever the new bytes of data arrives.
I need to save all the data to the buffer because after this I will parse the data to obtain only the binary image data and write it to a file.

Can anyone please help me out with the algorithm to do this.
Thank you very much! :)
Posted
Updated 4-Oct-12 5:32am
v2

Your recv code is okay. The algorithm you need: every time your recv() call returns with a piece of data you append it to your buffer - you commented the place where you would otherwise call your appender function. This appender func should do a minimal parsing on the mime data - it should be able to detect if the whole mime message has arrived and in this case you should break out of your recv loop and close the connection without performing any more recv() calls because that would result your application to hang up if the other side doesn't close the connection immediately after sending the full data. This is the same problem as with http clients that use blocking sockets like you, and the solution is also the same:

If you are not familiar with mime encoding, its a relatively simple to write a minimal "parser" that detects the end of the data without parsing it in detail. Take a look at the multipart mime message example here: http://en.wikipedia.org/wiki/MIME#Multipart_messages[^]
That is a "multipart/mixed" message not a "multipart/related" but it doesn't matter from your point of view because detecting the end of the mime data will be the same basically for each "multipart/something" message.

In the example the parts of the mime message are separated by the "--frontier" separator, and the whole multipart message is finished with the "--frontier--". You can easily write a mime parser that interprets the header of the multipart message, finds out the boundary (that is "frontier" in the example, and then you are ready to go and search for the finishing "--your_boundary_goes_here--" line. The boundary marks are always on a new line so its easy to go with the parsing line-by-line. You don't even have to care about the contents of the individual parts of the multipart message. Mime has hierarchy, each part can contain another multipart or whatever kind of mime block but those use different separators than the root message so you don't have to deal with those at all.
   
v2
Comments
BruhaMars 7-Oct-12 0:37am
   
Thank you pasztorpisti for your reply.
I modified my code to this:

char* g_szBuff = NULL;
int g_iBuffSize = 0;


void receivePacket(char* szData, int iLen);


void receivePacket(char* szData, int iLen)
{
int iNewSize;

if (iLen == 0);
{
return;
}

iNewSize = g_iszBuffSize + iLen;

if (g_szBuff == NULL)
{
g_szBuff = new char[iNewSize];
}
else
{
g_szBuff = (char*)realloc(iNewSize);
}
memcpy(&g_szBuff[iNewSize], szdata, iLen);
g_szBuffSize = iNewSize;
}


// Receive until the peer closes the connection
do
{

iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if ( iResult > 0 )
{
receivePacket(recvbuf, iResult);
printf("Bytes received: %d\n", iResult);
}
else if ( iResult == 0 )
{
printf("Connection closed\n");
}
else
{
printf("recv failed: %d\", WSAGetLastError());
}

}while( iResult > 0 );

However, when I tried printing the ending result of g_szBuff the data in it is incomplete. I only receive part of the whole data. Thank you!
xenotron 7-Oct-12 7:22am
   
Then its time to modify it again because its full of bugs. reallocing what you allocated with new, you should never mix new and malloc/realloc/free calls! You are overindexing: memcpy(&g_szBuff[iNewSize], szdata, iLen);. I'm not surprised you see just the part of the data. Couldn't you find these trivial bugs with a debugger???
Try this:-
C++
int rd;
char buffer[50000];
FILE* fout = fopen("mydata","w"); // open a file first
while(rd=read(mySock,buffer,50000))
{
  fwrite(buffer,1,rd,fout); // save all receive data into a file. No matter how large the data.
  //set break condition after end of read
  if(rd==0) break;
}
now parse your image data from mydata .
// sometimes rd never goes to 0 because of some others issue. That case you can use an timeout function inside while loop to detect end of data transfer. 
   
v2
Try a solution from the following link
Server Client Sockets[^]
   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900