Ok. This is a bit odd. Long story short. I am fething raw BGR images from a camera, compressing them to JPG with OpenCV and sending with UDP protocol to a PC. This is how I compress images:
// memblock contains raw image
IplImage* fIplImageHeader;
fIplImageHeader = cvCreateImageHeader(cvSize(160, 120), 8, 3);
fIplImageHeader->imageData = (char*) memblock;
// compress to JPG
vector<int> p;
p.push_back(CV_IMWRITE_JPEG_QUALITY);
p.push_back(75);
vector<unsigned char> buf;
cv::imencode(".jpg", fIplImageHeader, buf, p);
This is how I send them with UDP:
n_sent = sendto(sk,&*buf.begin(),(int)size,0,(struct sockaddr*) &server,sizeof(server));
This is how I receive them in a PC:
int iRcvdBytes=recvfrom(iSockFd,buff,bufferSize,0,
(struct sockaddr*)&cliAddr,(socklen_t*)&cliAddrLen);
// print how many bytes we have received
cout<<"Received "<<iRcvdBytes<<" bytes from the client"<<endl;
I am getting this output:
Received 57600 bytes from the client
Received 57600 bytes from the client
...
If I remove the JPG compression at the program fetching images from camera, the output is the same:
Received 57600 bytes from the client
Received 57600 bytes from the client
...
However, when I save the received image on a disk, it's size is around 7.8KB while uncompressed raw image saved to disk takes about 57KB space.
What's going on here?
The "size" you pass to send is the size of the compressed buffer, right? It's not obvious from your code snippets where "size" comes from (as ypnos suggests, I would have expected buf.size() ).
You don't use buf.size() when sending the packet. So you send more data than is actually contained in buf. In some cases you will get a segfault for that.
Related
I have work this for weeks, very hope for your help!!! please forgive my poor english.
First, I think it's necessary to describe the Application Scenario:
what data I want to decompress?----the data is come from the network traffic of the internet. In these traffic, there are some data are compressed by gzip and store in the http or tcp packet, if the data size is huge and large than the maxlength of tcp payload, it will be sliced and transmiss. I can extract the compressed data from these packet, and group these data by the tcp stream. so I can assure that the data extracted from these packets of one specific tcp stream is belong to Same data source. so the data is consist of many compressed data chunk, the Application Scenario require that you need to decompress the data immediately once recieved one packet. For each tcp stream, we maintain a z_stream data structure.
When does the program report an error? ----All of the error is "Z_DATA_ERROR: invalid distance too far back". then I find when the recieved packet is out-of-order or some packet is lossed, the error will happen!
One simple case:
Compressed data is split into multiple data blocks and stored in network data packets(p1, p2, p3, p4, p5, p6, p7), and then transmiss in one specific tcp stream. For each tcp stream, we maintain a z_stream data structure. Obviously, p1 include the gzip header 0x1f 0x8b 0x08...), but due to the Uncertainty in network transmission, the packet recieved may be out-of-order or loss, for example: (p1,p2,p5,p6,p7,p3,p4),the first two packet can decompree normally, but when decompress p5, the error occur(Z_DATA_ERROR).
SO, I have these problem:
Due to the application scenario, I need to decompress the data once recieved one packet with gzip content-encoding. So I want to know if zlib supports such a function----directly decompress a compressed block without having to consider the packet arrival order?
I also test the influce of packet recieved order: If I sort the data in its original order and then decompress it sequentially, it will decompress normally.
Thirdly, Logically speaking, for the packeted recieved order (p1,p2,p5,p6,p7,p3,p4), when decompress these packet sequentially, p1,p2 will decompress successfully, p5,p6,p7 will decompress failed, the next packet recieved is p3, Logically speaking, it should be decompress successfully, but when I test this case, it failed, I don't understand this.
I also found a confusing problem, which does not happen often: if I sort the packet as (p1,p2,p3,p5,p4...), Logically speaking, when decompress p5, it should report an error, buf it decompress sucessfully, I don't understand this.
the following is source code:
/**
* buf: the gzip compressed data that extract form tcp packet
*/
void dowithGzipDataByZlib(z_stream * p_zlib_strm, unsigned char * buf, int buflen)
{
int zlib_status = Z_OK;
int bytes_dc_now = 0;
unsigned char pNowResBuff[4096];
printf("-------\n");
(*p_zlib_strm).avail_in = buflen;
(*p_zlib_strm).next_in = buf;
do {
memset(pNowResBuff,0,4096);
(*p_zlib_strm).avail_out = 4096;
(*p_zlib_strm).next_out = pNowResBuff;
zlib_status = inflate (p_zlib_strm, Z_NO_FLUSH);
printf("inflate status:%d\n",zlib_status);
if(Z_OK != zlib_status && Z_STREAM_END!=zlib_status){
printf("(*p_zlib_strm).avail_in:%d\n",(*p_zlib_strm).avail_in);
printf("err msg:%s\n",p_zlib_strm->msg);
return ;
}
bytes_dc_now = 4096 - (*p_zlib_strm).avail_out;
// printf("bytes_dc_no:")
} while(0 == (*p_zlib_strm).avail_out) ;
printf("(*p_zlib_strm).avail_in:%d\n",(*p_zlib_strm).avail_in);
}
// under the dirpath, there are some compressed data extract from the packets of one specific tcp stream, and store them in "file_basename_%d" file. (%d is the recieve order num: 1,2,3,4...)
void read( char* dirpath, char* file_basename)
{
char filelist[99][255];
int file_count = listDir(dirpath, filelist, 99, 255);
char filepath[255];
z_stream zlib_strm = {0};
zlib_strm.zalloc = Z_NULL;
zlib_strm.zfree = Z_NULL;
zlib_strm.opaque = Z_NULL;
zlib_strm.next_in = Z_NULL;
zlib_strm.avail_in = 0;
inflateInit2 (& zlib_strm, 32 | MAX_WBITS);
FILE* fp;
char buf[2048];
// sort_file_ind: the array store the origin order of the compressed data.
int sort_file_ind[99] = {0,1,2,3,15,16,17,18,19,20,21,4,5,6,7,8,9,10,11,12,13,14};
for(int i=1;i<=file_count-2;i++)
{
memset(filepath,0,sizeof(filepath));
// snprintf(filepath,sizeof(filepath), "%s%s%d",dirpath,file_basename,sort_file_ind[i]);
snprintf(filepath,sizeof(filepath), "%s%s%d",dirpath,file_basename,i);
printf("%s\n",filepath);
fp = fopen(filepath,"r");
if(fp == NULL){
return;
}
fseek(fp, 0, SEEK_END);
int flen = ftell(fp);
fseek(fp, 0, SEEK_SET);
memset(buf,0,sizeof(buf));
int dlen = fread(buf, 1, flen, fp);
if(dlen != flen){
fclose(fp);
return;
}
printf("dlen:%d\n",dlen);
dowithGzipDataByZlib(&zlib_strm,(unsigned char *)buf,dlen);
fclose(fp);
}
}
char * dir = "/data/GzipDC/softDC/DocumentAnalyze/testbyzs/data/119.40.37.65.42050/";
char * base_filename = "119.40.37.65.42050>180.76.22.49.80_1_";
int main()
{
read(dir,base_filename);
return 0;
}
I've asked around and tried many things for days, and I really need someone with knowledge on the subject to weigh in here. Thanks for your time!
I am setting up a client server connection through sockets in C++. I am successfully connecting them but while sending filesize and file data i am receiving some garbage values also in my server.
I am firstly sending File Size through send system call from client and then sending file Buffer to server.
I have recv system call in server which is successfully receiving Filesize, but while getting File data after some bytes i am getting garbage.
Client Code
File = fopen("index.jpg", "rb");
if (!File)
{
MessageBox(L"Error while readaing the file");
}
fseek(File, 0, SEEK_END);
Size = ftell(File);
fseek(File, 0, SEEK_SET);
char* Buffer = new char[Size];
fread(Buffer, Size, 1, File);
char cSize[MAX_PATH];
sprintf(cSize, "%lu", Size);
send(Socket, cSize, MAX_PATH, 0); // File size
send(Socket, Buffer, Size, 0); // File Binary
Server Code
unsigned long Size;
char *Filesize = new char[1024];
if (recv(Sub, Filesize, 1024, 0)) // File size
{
Size = strtoul(Filesize, NULL, 0); //getting filesize
}
Buffer = new char[Size];
int reader = recv(Sub, Buffer, Size, 0);
Buffer[Size] = '\0';
if (reader == -1) // File Binary
{
MessageBox(L"Perror Recv");
}
else if (reader == 0)
{
MessageBox(L"Connection is Closed");
}
else
{
FILE *File;
File = fopen("test.jpg", "wb");
fwrite((const char*)Buffer, 1, Size, File);
MessageBox(L"DATA Received");
fclose(File);
}
One problem is that you aren't handling the return values from recv() correctly. For example:
if (recv(Sub, Filesize, 1024, 0)) // File size
... when the function quoted above returns, it has written some number of bytes (more than 0, less than 1025) into Filesize. How many? Your program doesn't know, because you didn't store the return value into a variable to find out (rather you only checked it to see if it was non-zero, or not, then discarded the value). Therefore, it's entirely likely that Filesize contains not only your file size value, but the some portion of your file's data as well... which is why that portion of your file's data won't get written to disk later on in your program.
A similar problem is here:
int reader = recv(Sub, Buffer, Size, 0);
You check reader to see if it is -1 or 0 (which is good), but in your final case you just fwrite() out Size bytes from the array, when Buffer contains reader bytes, not Size bytes (and reader could have any value between 1 and Size, depending on how many bytes the TCP stack decided to deliver to you in that particular recv() call.
One more problem is that you send MAX_PATH bytes for the file size, but you receive (up to) 1024 bytes for file size. Is MAX_PATH equal to 1024? If not, then even if recv() did fill out all 1024 bytes, your sender and receiver would still be out of sync with each other, since the excess bytes would show up in future recv() calls, or (alternatively) you'd get bytes from subsequent send() calls placed into your FileSize buffer.
So that's the direct problem -- I think the underlying problem is that you are making some assumptions about how TCP network works that are not true. In particular:
There is no guarantee of a one-to-one correspondence between send() and recv() calls. (TCP is a byte-stream protocol and doesn't do any data-framing)
You cannot rely on N bytes of data from a single call to send() being delivered via a single call to recv(). The bytes you send() will be delivered in order, but there are no guarantees about how many calls to recv() it will require to receive them all, nor about how many bytes any given call to recv() will write into your receive-buffer.
You cannot rely on recv() to fill up the entire buffer you passed to it. recv() will write as few or as many bytes as it wants to, and it's up to your code to handle it correctly regardless of how many bytes it gets per recv() call.
In practice, this means you'll need to call recv() in a loop, and keep careful track of the return value from each recv() call, so you always know exactly how many bytes you've received so far and therefore where inside your buffer the next recv() call should start writing at.
You are not handling the responses of send and recv function make sure you collect that as there are number of bytes send and receive and further use them were ever required.
I am new in socket programming. I have a client application written in c++ that connect to camera. And then Camera sends the packet of frames in chunks between 0 - 1460. I have used recv function to receive the packet. I saw soo many question in which it was clearly mentionthat recv function return the bytes received, but in my case recv function returning the value written in the 3rd parameter of the recv function i.e len. So is their anyway through whichI can find the actual bytes received.
I even try to use char* but that not even work.
So, anyone please tell me the solution.Any help will be appreciable. Thank in Advance
char *buf = new char[1461];
int bytes = recv(sock, buf, 2000, 0);
printf("%d", bytes);
that always print 2000.
because of that after the valid bytes in the buf their are unknown bytes that's results in unexpected Image.
First of all, your code has a bug (which leads to undefined behavior).
You have allocated 1461 bytes but you are trying to read more than that:
It should go like this:
vector<char> buf(5000); // you are using C++ not C
int bytes = recv(sock, buf.data(), buf.size(), 0);
std::cout << bytes;
Secondly result is as expected. Camera sends much more data than 2000 bytes, so I'm not surprised that number of bytes read covers whole requested size.
I am capturing some audio from my microphone using SFML.
The data is being stored in samples of type Int16*.
Int16* samples;
My question is. What should I do to this samples to stream it over a socket to be played in another place? I ask in relation of data type. Do I need to convert this Int16 array to another type? Or can I just send this Int16* as it is?
EDIT
void BroadcastRecorder::loadBufferFromSamples()
{
//m_samples is of type vector<Int16*>
if (!m_samples.empty()){
m_buffer.loadFromSamples(&m_samples[0], m_samples.size(), 1, getSampleRate());
m_samples.clear();
}
}
void Broadcaster::Send()
{
//load the buffer with the samples
if(!m_recorder->empty()){
m_recorder->loadBufferFromSamples();
const sf::SoundBuffer& buffer = m_recorder->getBuffer();
size_t dataLength = m_recorder->GetSamplesSize();
wxSocketClient * socket = new wxSocketClient(wxSOCKET_NOWAIT);
socket->Notify(false);
// ------------- DATA----------------------
wxString data = "";
wxString strToPrepend(_("--myboundary\r\nContent-Type: audio/wav\r\n"));
wxString strToAppend(_("\r\n--myboundary\r\n"));
// ------------- HEADER -----------------------
wxString header = "";
header.append("POST ");
header.append("/cgi-bin/operator/transmit");
header.append(" HTTP/1.0\r\n");
header.append("Content-Type: multipart/form-data; boundary=--myboundary\r\n");
header.append("Content-Length: " + wxString::Format(wxT("%i"),(dataLength + strToPrepend.Len() + strToAppend.Len()) ) + "\r\n");
header.append("Authorization: Basic keykeykeykey\r\n");
header.append("\r\n");
//-------------- CONNECTION ---------------
wxString host = _("192.168.50.11");
wxIPV4address * address = new wxIPV4address();
address->Hostname(host);
address->Service(8084);
if (socket->Connect(*address)){
//Write header
socket->Write(header.c_str(),header.Len());
//Write data
socket->Write(strToPrepend.c_str(),strToPrepend.Len());
const sf::Int16* samples = buffer.getSamples();
const char* bytesData = reinterpret_cast<const char*>(samples);
socket->Write(bytesData,dataLength);
socket->Write(strToAppend.c_str(),strToAppend.Len());
socket->Close();
}
delete socket;
delete address;
}
}
I am getting only some noises between gaps.
BTW. The audio is being sent to an IP camera p2 connector.
The data format is just the way your application treats them. After all you send raw bytes over a socket. And you can do it with anything you want
Int16 data;
const char* pBytesOfData = (const char*) &data;
int size = sizeof (Int16);
send( socket, pBytesOfdata, size, flags);
When the bytes arrive on the second end it is up to you to interpret them correctly. Probably you will want again treat them as Int16. You need to have a protocol (common way of communication) to do it right (maybe send size of the data at the begining of the transmission, etc).
You can also take a look on libraries that ease serialization: Boost.Asio and Boost.Serialization.
Firstly, You need to create and bind a socket. Then you have to send the data stored in "samples" to another peer by using socket API. For using socket API to send the data, you need to convert this data to char*. As send API of socket takes input of data you need to send as char*. For more information about sending you can go through this link. This is for windows. For Unix you can check the manpage for send API for unix.
Int16* is a pointer. The samples you get should also have an associated length. Your data will likely be between addresses: [samples, samples + length) (where samples is the address to the first sample).
To play the samples remotely (actual code will depend on what APIs you use):
open socket
in a loop
get samples from your microphone
transmit the data over socket
on the server, you will have to read samples in a loop and send them to whatever sound output API you use.
Sockets work with bytes, so in the end you will send bytes. As long as the way you interpret these bytes on the receiving side matches the data you sent, you can send whatever you want in those bytes.
In this case sending the samples directly without conversion seems the most trivial thing to do, but you will probably need to send the size of the sample before, most likely in a fixed length format, for example:
[size on 4 bytes][sample on `size` bytes]
[] [] [] [][] [] [] [] [] []
I would like to send/recieve image files and 2 ints as messages in a client server program.
I'm using QLocalSocket and QImage for this.
However I don't know how to read from the socket only after the image and the integers are fully written to the buffer, since the readyRead signal is already fired after the first couple of bytes.
Here's parts of my code:
// sending
QDataStream stream(socket);
stream << image << i << j;
// recieving
void MainWindow::readyRead() {
// ...
if (socket->bytesAvailable() > 400)
{
QByteArray b = socket->readAll();
QDataStream stream(&b, QIODevice::ReadOnly);
QImage image;
int i, j;
stream >> image >> i >> j;
// ...
}
}
I tried guessing the incoming file size, but since QImage is serialized to PNG the data size is variable and sometimes the end of the file doesn't get written to the buffer before I start to read it.
Is there an easy solution to this?
I would send a fixed size header first that describes the data being sent, specifically the type and size in bytes.
Then as you receive readReady events you pull whatever data is available into a buffer. Once you determine you have received all of the necessary data, you can stream it into a QImage object.
The BMP format has size information and PNG format has size information for each chunk. These are formats with what QImage serializes.
If you don't want to extract the information from raw data then serialize QImage first to QBuffer (so you know/control size and format better). Then stream that size and buffer.
Code example:
QBuffer buffer;
image.save(&buffer, "PNG", 100); //can change the compression level to suit the application - see http://qt-project.org/doc/qt-4.8/qimage.html#save
qint64 length = sizeof(quint32) + buffer.data().size(); //http://doc.qt.digia.com/4.7/datastreamformat.html
stream << length;
stream << buffer.data();
Then on the other end, first stream out the qint64 length so you know how big socket->bytesAvailable() has to be to stream out the full QByteArray. Then:
QByteArray ba;
stream >> ba;
QImage image = QImage::fromData(ba); // Get image from buffer data