I am using Namedpipes communication(C++) to transfer data between two processes. For the sake of comfort, I am using wstring to transfer the data and everything is fine at the transfer end. I am not able to receive the total data on the receiving end.
The following is the transfer end code.
wstringstream send_data;
send_data << "10" << " " << "20" << " " << "30" << " " << "40" << " " << "50" << " " << "60" << "\0" ;
DWORD numBytesWritten = 0;
result = WriteFile(
pipe, // handle to our outbound pipe
send_data.str().c_str(), // data to send
send_data.str().size(), // length of data to send (bytes)
&numBytesWritten, // will store actual amount of data sent
NULL // not using overlapped IO
);
The following is the receiving end code.
wchar_t buffer[128];
DWORD numBytesRead = 0;
BOOL result = ReadFile(
pipe,
buffer, // the data from the pipe will be put here
127 * sizeof(wchar_t), // number of bytes allocated
&numBytesRead, // this will store number of bytes actually read
NULL // not using overlapped IO
);
if (result) {
buffer[numBytesRead / sizeof(wchar_t)] = '\0'; // null terminate the string
wcout << "Number of bytes read: " << numBytesRead << endl;
wcout << "Message: " << buffer << endl;
}
The result in buffer contains only 10 20 30
Can someone please explain me why the data is truncated.
You are not sending all of the data with the WriteFile() function. You are sending send_data.str().size() number of bytes which is incorrect as size() gives you the number of characters and not the number of bytes. You can change your code to use:
send_data.str().size() * sizeof(wchar_t) / sizeof(char)
Which will send the correct amount of bytes.
Related
I am able to create a shared memory object, as well as open it using the guide from MSDN.
The first process creates it and keeps it open.
The second process inputs a string.
Then the first process will attempt to recover that string and display it, however I can't seem to get anything. It's always empty although it seems like the writing part is set up correctly.
I write a string to memory like this:
int MemoryMapper::Write(const std::string& data) {
m_pBuffer = (LPCTSTR)MapViewOfFile(m_OpenHandle, FILE_MAP_ALL_ACCESS, 0, 0, m_BufferSize);
if (m_pBuffer == NULL)
{
std::cerr << m_DebugErrorTitle << "Write(): " << MM_ERROR_MAPPING_FAILED << " {" << GetLastError() << "}" << std::endl;
Close();
return 0;
}
const char* cdata = _CharFromString(data);
int size = (lstrlen(cdata) * sizeof(const char*));
CopyMemory((PVOID)m_pBuffer, cdata, size);
m_WrittenSize += size;
if (m_Debug > 1) { std::cout << m_DebugTitle << "Wrote " << size << " bytes." << std::endl; }
return size;
}
Then I read it like so:
int MemoryMapper::Read(std::string& data) {
m_pBuffer = (LPCTSTR) MapViewOfFile(m_OpenHandle, FILE_MAP_ALL_ACCESS, 0, 0, m_BufferSize);
if (m_pBuffer == NULL)
{
std::cerr << m_DebugErrorTitle << "Read(" << m_MemoryName << "): " << MM_ERROR_MAPPING_FAILED << " {" << GetLastError() << "}" << std::endl;
Close();
return 0;
}
MessageBox(NULL, m_pBuffer, TEXT("TEST MESSAGE"), MB_OK);
int size = (lstrlen(m_pBuffer) * sizeof(const char*));
UnmapViewOfFile(m_pBuffer);
return size;
}
m_pBuffer is a LPCTSTR and m_BufferSize is 1024.
The name speficied for the object is the same on both ends. I've already made sure the creation and opening/closing part works.
The second process writes '8312.000000,8312.000000', a total of 92 bytes according to the code.
The reader's buffer is empty.
What am I doing wrong?
I've tried various data types, char, const char, string, tchar - same result.
8312.000000,8312.000000 is 23 characters in length.
std::string::c_str() returns a null-terminated char* pointer. lstrlen() returns the number of characters up to but not including the null terminator.
Write() is multiplying the string length by sizeof(const char*), which is 4 in a 32-bit process (8 in a 64-bit process). Write() is exceeding the bounds of data and attempting to copy 23 * 4 = 92 bytes into m_pBuffer. cdata is guaranteed to point at a buffer containing 24 bytes max (23 characters + 1 null terminator), so Write() is reaching into surrounding memory. That is undefined behavior, and anything could happen. In your case, you probably just ended up copying extra garbage into m_pBuffer. Write() could have easily crashed instead.
In fact, if data has more than 256 characters, Write() WOULD crash, because it would be trying to copy 257+ * 4 > 1024 bytes into m_pBuffer - more than MapViewOfFile() mapped access for.
You should be multiplying the string length by sizeof(std::string::value_type) instead, which is sizeof(char), which is always 1 (so you could just omit the multiplication).
Read() has the same sizeof() mistake, but it is also making the assumption that m_pBuffer is always null-terminated when calling lstrlen() and MessageBox(), but Write() does not guarantee that a null terminator is always present.
With that said, try something more like this instead:
int MemoryMapper::Write(const std::string& data)
{
// include the null terminator if there is room...
DWORD size = std::min(data.size() + 1, m_BufferSize);
char *pBuffer = (char*) MapViewOfFile(m_OpenHandle, FILE_MAP_WRITE, 0, 0, size);
if (!pBuffer)
{
DWORD errCode = GetLastError();
std::cerr << m_DebugErrorTitle << "Write(): " << MM_ERROR_MAPPING_FAILED << " {" << errCode << "}" << std::endl;
Close();
return 0;
}
CopyMemory(pBuffer, data.c_str(), size);
UnmapViewOfFile(pBuffer);
m_WrittenSize += size;
if (m_Debug > 1) {
std::cout << m_DebugTitle << "Wrote " << size << " bytes." << std::endl;
}
return size;
}
int MemoryMapper::Read(std::string& data)
{
char *pBuffer = (char*) MapViewOfFile(m_OpenHandle, FILE_MAP_READ, 0, 0, m_BufferSize);
if (!pBuffer)
{
DWORD errCode = GetLastError();
std::cerr << m_DebugErrorTitle << "Read(" << m_MemoryName << "): " << MM_ERROR_MAPPING_FAILED << " {" << errCode << "}" << std::endl;
Close();
return 0;
}
// check for a null terminator, but don't exceed the buffer...
char *terminator = std::find(pBuffer, pBuffer + m_BufferSize, '\0');
std::size_t len = std::distance(pBuffer, terminator);
data.assign(pBuffer, len);
UnmapViewOfFile(pBuffer);
MessageBoxA(NULL, data.c_str(), "TEST MESSAGE", MB_OK);
// include the null terminator if it was read...
return std::min(len + 1, m_BufferSize);
}
I am writing a simple user interface to communicate with an In-Circuit Serial Programmer. The intention is to remove the need for the end-user to type over a dozen cryptic commands via PuTTY, and in fact to remove the need for typing altogether as the user is inevitably wearing keyboard-unfriendly gloves. The process requires interaction with the user, so a simple batch script is not feasible.
I can find the correct COM port and successfully open it. I can send data, but the response is only ever the equivalent of "unknown command".
I shall refrain from posting the whole code as nobody will be able to recreate my circumstances. However, I can always add everything if necessary.
I open comms using CreateFile() and use WriteFile() or ReadFile() to communicate. For example:
if (!WriteFile(hSerial, "r rc.all\r\n", 10, &bytesRead, NULL))
cout << "Error sending message (" << GetLastError() << ")" << endl;
if (!ReadFile(hSerial, msgBuffer, 15, &bytesRead, NULL))
cout << "No message received" << endl
else
{
cout << "Bytes rcvd = " << bytesRead << endl;
for (int x=0; x<bytesRead; x++)
cout << (unsigned int) msgBuffer[x] << " ";
}
No matter what message I send (either "r rc.all" or "foobar") I always get the same response:
Bytes rcvd = 3
62 13 10
Which is >\r\n. I have tried slowing down the sending of characters to simulate them being typed, but this invokes the same response from the ICSP:
bool serialSend(LPCSTR MESSAGE, PHANDLE hSERIAL)
{
DWORD bytesWritten;
char writeBuff[2];
writeBuff[1] = '\0';
for (UINT x = 0; x <= strnlen(MESSAGE, 64); x++)
{
cout << MESSAGE[x];
writeBuff[0] = MESSAGE[x];
if (!WriteFile(*hSERIAL, writeBuff, 1, &bytesWritten, NULL))
cout << "\t\tERROR! (character '" << MESSAGE[x] << "', error " << GetLastError() << ")" << endl;
Sleep(100);
}
writeBuff[0] = '\n';
if (!WriteFile(*hSERIAL, writeBuff, 1, &bytesWritten, NULL))
cout << "\t\tERROR! (character 'LF', error " << GetLastError() << ")" << endl;
Sleep(100);
writeBuff[0] = '\r';
if (!WriteFile(*hSERIAL, writeBuff, 1, &bytesWritten, NULL))
cout << "\t\tERROR! (character 'CR', error " << GetLastError() << ")" << endl;
cout << endl;
return true;
}
I have set the parameters of the serial connection to match the settings in PuTTY - Byte length, stop bit, parity, flow control, etc. The fact that I get a response at all suggests the connections is not at fault.
What is wrong?
The problem turned out to be the \r\n combination sent at the end of the message.
Sending just \r or just \n does not work. However, sending (char) 13 does - even though that should be the same as \r.
There also needs to be a pause between the sending of each character; 1ms is sufficient.
I'm really tired with this - I tried to fix it for about 5 hours and I still can't semm to find a problem, maybe You guys can.
My problem is that recv at the client side always recv one less byte when I'm sending IP from server. And server is always sending the right ammount of data and right data and IP adress on client side always come without 1 number and it's always the first one so server send:
192.168.0.101
Client receive:
92.168.0.101
What is also important is that client's name is always received without any problems - it only happens with IP adress.
Take a closer look at that:
Server side sending data [2 strings - first is name of client and second is his IP adress]:
j is iterator of list to loop thourght all clients and client variable is the one which is asking for all client's data
std::cout << j->client_name << " ";
int lenght = j->client_name.length()+1 ; //+1 for '\0' byte at the client buffer
std::cout << "Lenght (+1): " << lenght << " ";
lenght = htonl(lenght); //change byte order to network
send(client->client_socket,(char*)&lenght,sizeof(int),0);
std::cout << "I have sent: " << send(client->client_socket,j->client_name.c_str(),j->client_name.length(),0) << std::endl;
std::cout << inet_ntoa(j->client_connection.sin_addr) << " "; //showing IP adress
unsigned lenght2 = strlen(inet_ntoa(j->client_connection.sin_addr))+1; //+1 for '\0' byte at the client buffer
std::cout << "Lenght (+1): " << lenght2 << " ";
unsigned realistic_lenght = lenght2;
lenght2 = htonl(lenght2);
send(client->client_socket,(char*)&lenght,sizeof(unsigned),0);
std::cout << "I have sent: " << send(client->client_socket,inet_ntoa(j->client_connection.sin_addr),realistic_lenght,0) << std::endl;
And as I said on server side everything seems to be good and here's code to receive data on client side:
char* data_buffor;
int lenght = 0;
recv(data.client_socket,(char*)&lenght,sizeof(int),0);
lenght = ntohl(lenght);
std::cout << "I have received: " << lenght << std::endl;
data_buffor = new char[lenght];
if (data_buffor != NULL) std::cout << "ALLOCATION WAS SUCCESFULL" << std::endl;
std::cout << "I have received: " << recv(data.client_socket,data_buffor,lenght,0) << std::endl;
data_buffor[lenght-1] = '\0';
temp.client_name = data_buffor; // everything is fine here
delete data_buffor;
data_buffor = NULL;
unsigned lenght2 = 0;
recv(data.client_socket,(char*)&lenght2,sizeof(unsigned),0);
lenght2 = ntohl(lenght2);
std::cout << "I have received: " << lenght2 << std::endl; // I DONT KNOW WHY BUT HERE I GET CRAZY NUMBERS LIKE 3203 and I should get 14 with IP: 192.168.0.101 + one byte for '\0' I think that may be causing all problems but I have no idea how to fix it.
data_buffor = new char[lenght2];
if (data_buffor != NULL) std::cout << "ALLOCATION WAS SUCCESFULL" << std::endl;
std::cout << "I have received " << recv(data.client_socket,data_buffor,lenght2,0) << std::endl;
temp.client_ip_adress = data_buffor;
all_clients.push_back(temp);
delete data_buffor
data_buffor = NULL;
Any help would be highly appreciated.
When the server sends the client name, it is sending the length as the length of the string + 1 to include the terminating NULL character. However, the value returned by std::string::length() does NOT include the terminating NULL, so the server is not actually sending the terminating NULL to the client. When the client then reads the name, it reads the first character of the IP address as the terminating NULL of the name, but you never notice that because the client overwrites that byte in data_buffor with '\0' instead of relying on the server to send the '\0'.
I am developing an application with C++ and having some difficulty with boost sockets. The server sends an image but not all the bytes are received by the client; the client always receives about 500 bytes less than the server sent. Provided below is the pertinent code and screenshots of the program running.
Server code:
int sent = boost::asio::write(*socket, response, boost::asio::transfer_all(), error);
std::cout << "Sent: " << sent << std ::endl;
Client code (I know that read_some will block if the total bytes sent by the server is divisible by 10000; this code is just for testing):
int len = 0;
int count = 0;
do {
len = socket->read_some( boost::asio::buffer( imageData, 10000 ) );
count += len;
std::cout << "len: " << len << std::endl;
std::cout << "count: " << count << std::endl;
} while(len == 10000);
std::cout << "Image Received of size: " << count << std::endl;
Screenshot of server:
Screenshot of client:
Thanks for your time; any help or suggestions would be greatly appreciated.
There're no guarantee you'll receive complete buffers of 10000 bytes.
I'd recommend following approach:
To send some binary data w/o any explicit terminator, first send its size and only then data itself. In this case client will know how many data in this chunk it should receive.
Next iteration of my question:
Thank you for your inputs, it has helped me to understand a little bit more about the Frame and inputSamples utility.
I’ve done modifications to my source code with the new knowledge you’ve given me. But I still have problems, so I might not have understood fully what you meant.
Here is my OpenFile function, sorry for the name but I’ll refactor later; when it’ll work =)
//-----------------------------------------------------------------------------
/*
This Function Open a File containing the Audio, Binary, Data.
*///___________________________________________________________________________
const short* OpenFile(const char* fileName, long& fileSize, WavFormat* wav)
{
// ouvre le fichier
ifstream file;
file.open((char*)fileName, ios::binary|ios::in);
if (file.good())
{
// Read the WAV's Header
wav = CheckWavHeader(file, wav);
cout << "chunkID: " << wav->chunkID <<'\n';
cout << "chunkSize: " << wav->chunkSize <<'\n';
cout << "format: " << wav->format <<'\n';
cout << "subChunk1ID: " << wav->subChunk1ID <<'\n';
cout << "subChunk1Size: " << wav->subChunk1Size <<'\n';
cout << "audioFormat: " << wav->audioFormat <<'\n'; // audioFormat == 1, alors PCM 16bits
cout << "numChannels: " << wav->numChannels <<'\n';
cout << "sampleRate: " << wav->sampleRate <<'\n';
cout << "byteRate: " << wav->byteRate <<'\n';
cout << "blockAlign: " << wav->blockAlign <<'\n';
cout << "bitsPerSample: " << wav->bitsPerSample <<'\n';
cout << "subChunk2ID: " << wav->subChunk2ID <<'\n';
cout << "subChunk2Size: " << wav->subChunk2Size <<'\n';
// Get the file’s size
file.seekg(0L, ios::end);
fileSize = ((long)file.tellg() - DATA_POS);
file.seekg(DATA_POS, ios::beg); // back to the data.
// Read the Data into the Buffer
uint nbSamples = fileSize / sizeof(short);
short* inputArray = new short[nbSamples];
file.read((char*)inputArray, fileSize);
// Close the file and return the Data
file.close();
return (const short*)inputArray;
}
else
{
exit(-1);
}
}
I’m opening the file, checking its size, create a short buffer and read the wav’s data into the short buffer and finally I return it.
In the main, for now I commented the G711 decoder.
When I run the application, the faacEncOpen gives me 2048 for inputSamples (it’s logic since I have 2 channels in the Wav’s file for a FRAME_LEN of 1024).
So if I understood correctly, 1 Frame == 2048 samples for my application. So for each Frame I call the faacEncEncode, I give the tmpInputBuffer that is a buffer of the same size as inputSamples at the inputBuffer[i * inputSamples] index.
//-----------------------------------------------------------------------------
/*
The Main entry Point of the Application
*///_____________________________________________________________________________
int main()
{
// Get the File's Data
WavFormat* wav = new WavFormat;
long fileSize;
const short* fileInput = OpenFile("audioTest.wav", fileSize, wav);
// G711 mu-Law Decoder
//MuLawDecoder* decoder = new MuLawDecoder();
//short* inputBuffer = decoder->MuLawDecode_shortArray((byte*)fileInput, (int)nbChunk);
short* inputBuffer = (short*)fileInput;
// Info for FAAC
ulong sampleRate = wav->sampleRate;
uint numChannels = wav->numChannels;
ulong inputSamples;
ulong maxOutputBytes;
// Ouvre l'Encodeur et assigne la Configuration.
faacEncHandle hEncoder = faacEncOpen(sampleRate, numChannels, &inputSamples, &maxOutputBytes);
faacEncConfigurationPtr faacConfig = faacEncGetCurrentConfiguration(hEncoder);
faacConfig->inputFormat = FAAC_INPUT_16BIT;
faacConfig->bitRate = 64000;
int result = faacEncSetConfiguration(hEncoder, faacConfig);
/*Input Buffer and Output Buffer*/
byte* outputBuffer = new byte[maxOutputBytes];
int nbBytesWritten = 0;
Sink* sink = new Sink();
uint nbFrame = fileSize / inputSamples;
int32_t* tmpInputBuffer = new int32_t[inputSamples];
for (uint i = 0; i < nbFrame; i++)
{
strncpy((char*)tmpInputBuffer, (const char*)&inputBuffer[i * inputSamples], inputSamples);
nbBytesWritten = faacEncEncode(hEncoder, tmpInputBuffer, inputSamples, outputBuffer, maxOutputBytes);
cout << 100.0 * (float)i / nbFrame << "%\t nbBytesWritten = " << nbBytesWritten << "\n";
if (nbBytesWritten > 0)
{
sink->AddAACStream(outputBuffer, nbBytesWritten);
}
}
sink->WriteToFile("output.aac");
// Close AAC Encoder
faacEncClose(hEncoder);
// Supprimer tous les pointeurs
delete sink;
//delete decoder;
delete[] fileInput;
//delete[] inputBuffer;
delete[] outputBuffer;
delete[] tmpInputBuffer;
system("pause");
return 0;
}
When the output Data is Dumped into an .acc file (as RAW AAC), I use the application mp4muxer.exe to create an .mp4 file to listen to the final converted sound. But the sound is not good at all...
I'm wondering if there is something I'm not seeing or do not unserstand that I should.
Thank you in advance for your useful inputs.
Each call to faacEncEncode encodes inputSamples samples, not just one. Your main loop should read that many samples from the WAV file into the input buffer, then call faacEncEncode once for that buffer, and finally write the output buffer to the AAC file.
It's possible that I've misunderstood what you're doing (if so, it would be useful to know: (1) What's the OpenFile function you're calling, and does it (despite its name) actually read the file as well as opening it? (2) How is inputBuffer set up?) but:
faacEncEncode expects to be given a whole frame's worth of samples. A frame is the number of samples you got passed back in inputSamples when you called faacEncOpen. (You can give it less than a whole frame if you've reached the end of the input, of course.)
So you're getting 460 and 539 bytes for each of two frames -- not for 16 bits in each case. And it looks as if your input-data pointers are actually offset by only one sample each time, so you're handing it badly overlapping frames. (And the wrong number of them; nbChunk is not the number of frames you have.)