How to properly delimit multiple images before sending them over a socket - c++

let's say I need to send, for instance, five images from a client to a server over a socket and that I want to do it at once (not sending one and waiting for an ACK).
Questions:
I'd like to know if there are some best practices or guidelines for delimiting the end of each one.
What would be the safest approach for detecting the delimiters and processing each image once in the server? (In C/C++ if possible)
Thanks in advance!

Since images are binary data, it would be difficult to come up with delimiter that cannot be contained in the image. (And ultimately confusing the receiving side)
I would advice you to create a header that would be placed at the beginning of the transmission, or at the beginning of each image.
An example:
struct Header
{
uint32_t ImageLength;
// char ImageName[128];
} __attribute__(packed);
The sender should prepend this before each image and fill in the length correctly. The receiver would then know when the image ends and would expect another Header structure at that position.
The attribute(packed) is a safety, that makes sure the header will have the same alignment even if you compile server and client with different GCC versions. It's recomended in cases where structures are interpreted by different processes.
Data Stream:
Header
Image Data
Header
Image Data
Header
Image Data
...

You can use these function to send files (from client in java) to a server (in C). The idea is to send 4 bytes which indicates the file's size followed by the file content, when all files have been sent, send 4 bytes (all set to 0 zero) to indicate the end of the transfer.
// Compile with Microsoft Visual Studio 2008
// path, if not empty, must be ended with a path separator '/'
// for example: "C:/MyImages/"
int receiveFiles(SOCKET sck, const char *pathDir)
{
int fd;
long fSize=0;
char buffer[8 * 1024];
char filename[MAX_PATH];
int count=0;
// keep on receiving until we get the appropiate signal
// or the socket has an error
while (true)
{
if (recv(sck, buffer, 4, 0) != 4)
{
// socket is closed or has an error
// return what we've received so far
return count;
}
fSize = (int) ((buffer[0] & 0xff) << 24) |
(int) ((buffer[1] & 0xff) << 16) |
(int) ((buffer[2] & 0xff) << 8) |
(int) (buffer[3] & 0xff);
if (fSize == 0)
{
// received final signal
return count;
}
sprintf(filename, "%sIMAGE_%d.img", pathDir, count+1);
fd = _creat(filename, _S_IREAD | _S_IWRITE);
int iReads;
int iRet;
int iLeft=fSize;
while (iLeft > 0)
{
if (iLeft > sizeof(buffer)) iReads = sizeof(buffer);
else iReads=iLeft;
if ((iRet=recv(sck, buffer, iReads, 0)) <= 0)
{
_close(fd);
// you may delete the file or leave it to inspect
// _unlink(filename);
return count; // socket is closed or has an error
}
iLeft-=iRet;
_write(fd, buffer, iRet);
}
count++;
_close(fd);
}
}
The client part
/**
* Send a file to a connected socket.
* <p>
* First it send the file size if 4 bytes then the file's content.
* </p>
* <p>
* Note: File size is limited to a 32bit signed integer, 2GB
* </p>
*
* #param os
* OutputStream of the connected socket
* #param fileName
* The complete file's path of the image to send
* #throws Exception
* #see {#link receiveFile} for an example on how to receive the file from the other side.
*
*/
public void sendFile(OutputStream os, String fileName) throws Exception
{
// File to send
File myFile = new File(fileName);
int fSize = (int) myFile.length();
if (fSize == 0) return; // No empty files
if (fSize < myFile.length())
{
System.out.println("File is too big'");
throw new IOException("File is too big.");
}
// Send the file's size
byte[] bSize = new byte[4];
bSize[0] = (byte) ((fSize & 0xff000000) >> 24);
bSize[1] = (byte) ((fSize & 0x00ff0000) >> 16);
bSize[2] = (byte) ((fSize & 0x0000ff00) >> 8);
bSize[3] = (byte) (fSize & 0x000000ff);
// 4 bytes containing the file size
os.write(bSize, 0, 4);
// In case of memory limitations set this to false
boolean noMemoryLimitation = true;
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
try
{
if (noMemoryLimitation)
{
// Use to send the whole file in one chunk
byte[] outBuffer = new byte[fSize];
int bRead = bis.read(outBuffer, 0, outBuffer.length);
os.write(outBuffer, 0, bRead);
}
else
{
// Use to send in a small buffer, several chunks
int bRead = 0;
byte[] outBuffer = new byte[8 * 1024];
while ((bRead = bis.read(outBuffer, 0, outBuffer.length)) > 0)
{
os.write(outBuffer, 0, bRead);
}
}
os.flush();
}
finally
{
bis.close();
}
}
To send the files from the client:
try
{
// The file name must be a fully qualified path
sendFile(mySocket.getOutputStream(), "C:/MyImages/orange.png");
sendFile(mySocket.getOutputStream(), "C:/MyImages/lemmon.png");
sendFile(mySocket.getOutputStream(), "C:/MyImages/apple.png");
sendFile(mySocket.getOutputStream(), "C:/MyImages/papaya.png");
// send the end of the transmition
byte[] buff = new byte[4];
buff[0]=0x00;
buff[1]=0x00;
buff[2]=0x00;
buff[3]=0x00;
mySocket.getOutputStream().write(buff, 0, 4);
}
catch (Exception e)
{
e.printStackTrace();
}

If you cannot easily send a header containing the length, use some likely delimiter. If the images are not compressed and consist of bitmap-stype data, maybe 0xFF/0XFFFF/0xFFFFFFF as fully-saturated luminance values are usually rare?
Use an escape-sequence to eliminate any instances of the delimiter that turn up inside your data.
This does mean iterating all the data at both ends, but depending on your data flows, and what is being done anyway, it may be a useful solution :(

Related

Boost C++ UDP Socket stops receive after N packages

I am sending udp packages from server to client. At the server side I split data into packages by 500 bytes, and sent to client. The client receives the packages and accumulate received data and deserializes an object.
The problem is that client receive 133 packages maximum and stops like nothing else was sent to socket, but server send whole object (1238 packages). And this problem exists in Windows only, but works perfectly under OSX.
Here is a server code sending packages:
// sends #buffer of size #length to #endpoint
// #buffer already contains a header, and the method splits #buffer into chunks and send it one by one
void server::send_package(char* buffer, int length, udp::endpoint endpoint){
if (length > BUFFER){
protocol::header header;
int dataLength = length - sizeof (header);
// copy header from buffer
memcpy(&header, buffer, sizeof(header));
header.isEnd = false;
int position = 0;
// allocate memory to collect data to send
char* data_to_send = new char[dataLength];
// copy data
memcpy(data_to_send, &buffer[sizeof(header)], dataLength);
header.totalPackages = dataLength/(BUFFER-sizeof (header));
// create chucks of data and send
while (position < dataLength){
int frame_size = BUFFER;
header.currentPackage++;
if (dataLength-position+sizeof (header) <= BUFFER) {
header.isEnd = true;
frame_size = dataLength-position+sizeof (header);
}
char* temp_buffer = new char[frame_size];
header.length = frame_size-sizeof(header);
// set the header of a chunk
memcpy(temp_buffer, &header, sizeof(header));
// set data to chunk
memcpy(&temp_buffer[sizeof (header)], &data_to_send[position], frame_size-sizeof(header));
// send chunk
socket->send_to(boost::asio::buffer(temp_buffer, frame_size), endpoint);
socket->wait(boost::asio::ip::tcp::socket::wait_write);
position += frame_size-sizeof(header);
}
} else {
socket->async_send_to(boost::asio::buffer(buffer, length), endpoint,
boost::bind(&server::release_sent_buffer,
this,
buffer, length)
);
}
}
Here is the client receives packages:
void connectionManager::handle_receive( const boost::system::error_code &error,
std::size_t size,
udp::endpoint* ep) {
if (size > 0) {
// _lock.try_lock();
protocol::header header;
memcpy(&header, &recv_buffer, sizeof(header));
logg("response from server received " + boost::asio::ip::address_v4(header.ip).to_string());
logg("received header:");
logg(protocol::getHeaderInfo(header));
std::stringstream ss;
ss << "header.length = " << header.length;
logg(ss.str().c_str());
udp::endpoint endpoint(boost::asio::ip::address_v4(header.ip), _server_port);
switch (header.command) {
case protocol::commands::server_instance_instruments_state_response: {
package_chain chain(size-sizeof(header));
memcpy(chain.data, &recv_buffer[sizeof(header)], size-sizeof(header));
packages[header.id].push_back(chain);
// at Windows machine the last package is #133. But 1248 packages expected.
// WHY????...
int packs = (packages[header.id].size());
if (header.isEnd) {
char* buf = getDataFromPackages(header.id, header.length);
std::stringstream str;
str << buf;
boost::archive::text_iarchive ar(str);
instance_plugin_information* inst_inf;
inst_inf = new instance_plugin_information();
try {
ar & inst_inf;
if (onPluginStateResponse != nullptr) {
onPluginStateResponse(*inst_inf);
}
} catch (const std::exception& e) {
}
}
break;
}
}
// We will hang on this line when package #133 received.
socket->wait(boost::asio::ip::tcp::socket::wait_read);
connectionManager::start_receive();
}
I just don't understand what I am missing? Why client receives exactly 133 packages (133 x 500 bytes) and then drops?
I have changed the code in many ways, but with no luck. The last thing I added is
socket->wait(boost::asio::ip::tcp::socket::wait_read);
before I call start_receive() again, and the program hands on this line exactly when package #133 is received.
Please help. I am close to give up and become a pizza delivery guy.

parsing complete messages from serial port

I am trying to read complete messages from my GPS via serial port.
The message I am looking for starts with:
0xB5 0x62 0x02 0x13
So I read from the serial port like so
while (running !=0)
{
int n = read (fd, input_buffer, sizeof input_buffer);
for (int i=0; i<BUFFER_SIZE; i++)
{
if (input_buffer[i]==0xB5 && input_buffer[i+1]== 0x62 && input_buffer[i+2]== 0x02 && input_buffer[i+3]== 0x13 && i<(BUFFER_SIZE-1) )
{
// process the message.
}
}
The problem I am having is that I need to get a complete message. Half of a message could be in the buffer one iteration. And the other half could come into the message the next iteration.
Somebody suggested that free the buffer up from the complete message. And then I move the rest of data in the buffer to the beginning of the buffer.
How do I do that or any other way that make sure I get every complete selected message that comes in?
edit//
I want a particular class and ID. But I can also read in the length
To minimize the overhead of making many read() syscalls of small byte counts, use an intermediate buffer in your code.
The read()s should be in blocking mode to avoid a return code of zero bytes.
#define BLEN 1024
unsigned char rbuf[BLEN];
unsigned char *rp = &rbuf[BLEN];
int bufcnt = 0;
static unsigned char getbyte(void)
{
if ((rp - rbuf) >= bufcnt) {
/* buffer needs refill */
bufcnt = read(fd, rbuf, BLEN);
if (bufcnt <= 0) {
/* report error, then abort */
}
rp = rbuf;
}
return *rp++;
}
For proper termios initialization code for the serial terminal, see this answer. You should increase the VMIN parameter to something closer to the BLEN value.
Now you can conveniently access the received data a byte at a time with minimal performance penalty.
#define MLEN 1024 /* choose appropriate value for message protocol */
unsigned char mesg[MLEN];
while (1) {
while (getbyte() != 0xB5)
/* hunt for 1st sync */ ;
retry_sync:
if ((sync = getbyte()) != 0x62) {
if (sync == 0xB5)
goto retry_sync;
else
continue; /* restart sync hunt */
}
class = getbyte();
id = getbyte();
length = getbyte();
length += getbyte() << 8;
if (length > MLEN) {
/* report error, then restart sync hunt */
continue;
}
for (i = 0; i < length; i++) {
mesg[i] = getbyte();
/* accumulate checksum */
}
chka = getbyte();
chkb = getbyte();
if ( /* valid checksum */ )
break; /* verified message */
/* report error, and restart sync hunt */
}
/* process the message */
switch (class) {
case 0x02:
if (id == 0x13) {
...
...
You can break the read into three parts. Find the start of a message. Then get the LENGTH. Then read the rest of the message.
// Should probably clear these in case data left over from a previous read
input_buffer[0] = input_buffer[1] = 0;
// First make sure first char is 0xB5
do {
n = read(fd, input_buffer, 1);
} while (0xB5 != input_buffer[0]);
// Check for 2nd sync char
n = read(fd, &input_buffer[1], 1);
if (input_buffer[1] != 0x62) {
// Error
return;
}
// Read up to LENGTH
n = read(fd, &input_buffer[2], 4);
// Parse length
//int length = *((int *)&input_buffer[4]);
// Since I don't know what size an int is on your system, this way is better
int length = input_buffer[4] | (input_buffer[5] << 8);
// Read rest of message
n = read(fd, &input_buffer[6], length);
// input_buffer should now have a complete message
You should add error checking...

range downloads in http

I need to download a html page in chunks. I had build a GET reuest whick can download a certain range of data. But i am unsuccessful in doing this in a repetitive manner.
Basically I have to reciver first 0-99 bytes then 100-199 and so on...
Also I would be grateful to know how toh know the exact size of receiving file beforehand using c or c++ code.
Following is my code.
i have exempted connectig to sockets etc. as it have been done successfully.
int c=0,s=0;
while(1)
{
get = build_get_query(host, page,s);
c+=1;
fprintf(stderr, "Query is:\n<<START>>\n%s<<END>>\n", get);
//Send the query to the server
int sent = 0;
cout<<"sending "<<c<<endl;
while(sent < strlen(get))
{
tmpres = send(sock, get+sent, strlen(get)-sent, 0);
if(tmpres == -1)
{
perror("Can't send query");
exit(1);
}
sent += tmpres;
}
//now it is time to receive the page
memset(buf, 0, sizeof(buf));
int htmlstart = 0;
char * htmlcontent;
cout<< "reciving "<<c<<endl;
while((tmpres = recv(sock, buf, BUFSIZ, 0)) > 0)
{
if(htmlstart == 0)
{
/* Under certain conditions this will not work.
* If the \r\n\r\n part is splitted into two messages
* it will fail to detect the beginning of HTML content
*/
htmlcontent = strstr(buf, "\r\n\r\n");
if(htmlcontent != NULL)
{
htmlstart = 1;
htmlcontent += 4;
}
}
else
{
htmlcontent = buf;
}
if(htmlstart)
{
fprintf(stdout, htmlcontent);
}
memset(buf, 0, tmpres);
}
if(tmpres < 0)
{
perror("Error receiving data");
}
s+=100;
if(c==5)
break;
}
char *build_get_query(char *host, char *page,int i)
{
char *query;
char *getpage = page;
int j=i+99;
char tpl[100] = "GET /%s HTTP/1.1\r\nHost: %s\r\nRange: bytes=%d-%d\r\nUser- Agent: %s\r\n\r\n";
if(getpage[0] == '/')
{
getpage = getpage + 1;
fprintf(stderr,"Removing leading \"/\", converting %s to %s\n", page, getpage);
}
query = (char *)malloc(strlen(host)+strlen(getpage)+8+strlen(USERAGENT)+strlen(tpl)-5);
sprintf(query, tpl, getpage, host, i , j, USERAGENT);
return query;
}
Also I would be grateful to know how toh know the exact size of receiving file beforehand using c or c++ code.
If the server supports a range request to the specific resource (which is not guaranteed) then the answer will look like this:
HTTP/1.1 206 partial content
Content-Range: bytes 100-199/12345
This means that the response will contain the bytes 100..199 and that the total size of the content is 12345 bytes.
There are lots of questions here which deal with parsing HTTP headers so I will not go into the detail on how to specifically use C/C++ to extract these data from the header.
Please note also that you are doing a HTTP/1.1 request and thus must deal with possible chunked responses and implicit keep alive. I really recommend to use existing HTTP libraries instead of doing it all by hand and doing it wrong. If you really want to implement it all by your own please study the specification of HTTP.

How Can I Reduce The Memory Useage For a Huge File Transfer?

I have to transfer some huge files (2GB-ish) to a web service:
public bool UploadContent(System.Web.HttpContext context)
{
var file = context.Request.Files[0];
var fileName = file.FileName;
byte[] fileBytes = new Byte[file.ContentLength];
file.InputStream.Read(fileBytes, 0, fileBytes.Length);
client.createResource(fileBytes);
}
The HttpContext already has the contents of the file in File[0], but I can't see a way to pass those bytes to the createResource(byte[] contents) method of the web service without making a copy as a byte array... so I am eating memory like candy.
Is there a more efficient way to do this?
EDIT client.createResource() is part of a COTS product and modification is outside our control.
Rather than sending the whole bytes you can send the chunks of the files. Seek the file for step by step upload and merge the next chunk to already save bytes on server.
You need to update your client.CreateResource method only if you're allowed to modify that method :)
Add following parameters:
string fileName // To locate the file name when you start sending the chunks
byte[] buffer // chunk that would be sent to server via webservice
long offset // Information that will tell you how much data is already uploaded, so that you can seek the file and merge the buffer.
Now your method will look like:
public bool CreateResource(string FileName, byte[] buffer, long Offset)
{
bool retVal = false;
try
{
string FilePath = "d:\\temp\\uploadTest.extension";
if (Offset == 0)
File.Create(FilePath).Close();
// open a file stream and write the buffer.
// Don't open with FileMode.Append because the transfer may wish to
// start a different point
using (FileStream fs = new FileStream(FilePath, FileMode.Open,
FileAccess.ReadWrite, FileShare.Read))
{
fs.Seek(Offset, SeekOrigin.Begin);
fs.Write(buffer, 0, buffer.Length);
}
retVal = true;
}
catch (Exception ex)
{
// Log exception or send error message to someone who cares
}
return retVal;
}
Now to read the file in chunks from the InputStream of HttpPostedFile try below code:
public bool UploadContent(System.Web.HttpContext context)
{
//the file that we want to upload
var file = context.Request.Files[0];
var fs = file.InputStream;
int Offset = 0; // starting offset.
//define the chunk size
int ChunkSize = 65536; // 64 * 1024 kb
//define the buffer array according to the chunksize.
byte[] Buffer = new byte[ChunkSize];
//opening the file for read.
try
{
long FileSize = file.ContentLength; // File size of file being uploaded.
// reading the file.
fs.Position = Offset;
int BytesRead = 0;
while (Offset != FileSize) // continue uploading the file chunks until offset = file size.
{
BytesRead = fs.Read(Buffer, 0, ChunkSize); // read the next chunk
if (BytesRead != Buffer.Length)
{
ChunkSize = BytesRead;
byte[] TrimmedBuffer = new byte[BytesRead];
Array.Copy(Buffer, TrimmedBuffer, BytesRead);
Buffer = TrimmedBuffer; // the trimmed buffer should become the new 'buffer'
}
// send this chunk to the server. it is sent as a byte[] parameter,
// but the client and server have been configured to encode byte[] using MTOM.
bool ChunkAppened = client.createResource(file.FileName, Buffer, Offset);
if (!ChunkAppened)
{
break;
}
// Offset is only updated AFTER a successful send of the bytes.
Offset += BytesRead; // save the offset position for resume
}
}
catch (Exception ex)
{
}
finally
{
fs.Close();
}
}
Disclaimer: I haven't tested this code. This is a sample code to show how large file upload can be achieved without hampering the memory.
Ref: Source article.

zlib's uncompress() strangely returning Z_BUF_ERROR

I'm writing Qt-based client application. It connects to remote server using QTcpSocket. Before sending any actual data it needs to send login info, which is zlib-compressed json.
As far as I know from server sources, to make everything work I need to send X bytes of compressed data following 4 bytes with length of uncompressed data.
Uncompressing on server-side looks like this:
/* look at first 32 bits of buffer, which contains uncompressed len */
unc_len = le32toh(*((uint32_t *)buf));
if (unc_len > CLI_MAX_MSG)
return NULL;
/* alloc buffer for uncompressed data */
obj_unc = malloc(unc_len + 1);
if (!obj_unc)
return NULL;
/* decompress buffer (excluding first 32 bits) */
comp_p = buf + 4;
if (uncompress(obj_unc, &dest_len, comp_p, buflen - 4) != Z_OK)
goto out;
if (dest_len != unc_len)
goto out;
memcpy(obj_unc + unc_len, &zero, 1); /* null terminate */
I'm compressing json using Qt built-in zlib (I've just downloaded headers and placed it in mingw's include folder):
char json[] = "{\"version\":1,\"user\":\"test\"}";
char pass[] = "test";
std::auto_ptr<Bytef> message(new Bytef[ // allocate memory for:
sizeof(ubbp_header) // + msg header
+ sizeof(uLongf) // + uncompressed data size
+ strlen(json) // + compressed data itself
+ 64 // + reserve (if compressed size > uncompressed size)
+ SHA256_DIGEST_LENGTH]);//+ SHA256 digest
uLongf unc_len = strlen(json);
uLongf enc_len = strlen(json) + 64;
// header goes first, so server will determine that we want to login
Bytef* pHdr = message.get();
// after that: uncompressed data length and data itself
Bytef* pLen = pHdr + sizeof(ubbp_header);
Bytef* pDat = pLen + sizeof(uLongf);
// hash of compressed message updated with user pass
Bytef* pSha;
if (Z_OK != compress(pLen, &enc_len, (Bytef*)json, unc_len))
{
qDebug("Compression failed.");
return false;
}
Complete function code here: http://pastebin.com/hMY2C4n5
Even though server correctly recieves uncompressed length, uncompress() returning Z_BUF_ERROR.
P.S.: I'm actually writing pushpool's client to figure out how it's binary protocol works. I've asked this question on official bitcoin forum, but no luck there. http://forum.bitcoin.org/index.php?topic=24257.0
Turns out it was server-side bug. More details in bitcoin forum thread.