Artema Hybrid communication with c++ on Linux - c++

I am currently trying to integrate a POS system with an Artema Hybrid CC handheld. I am wondering if anyone else has worked on this or something similar.
I can read from the device, that is I receive the ENQ, and send back an ACK in a thread, and I keep it open for reading/writing, but everything I try to write from it simply does nothing.
Here is the code for the function to write the data:
void PayLife::sendPayLifeData(QString data) {
int len = data.length();
int i = 0;
char lrc = 0;
char stx = 0x02;
char etx = 0x03;
char ack = 0x06;
char * bytes;
int ret;
char buffer[132];
bytes = (char *) malloc(sizeof(char) * len + 10);
strcpy(bytes,data.toLatin1().data());
qDebug() << "PayLife Sending data: " << data << " of len " << QString::number(len) <<
" " << " Bytes is: " << bytes ;
while (i < len) {
lrc ^= bytes[i];
i++;
}
/* sprintf(buffer,"%c%c%s%c%c",ack,stx,bytes,etx,lrc);
for (i = 0; i < strlen(buffer); i++) {
printf("c: %X ", buffer[i]);
}
printf(" [[ %s ]] \n", buffer); */
qDebug() << "Starting";
write(this->descriptor,&ack,1);
usleep(100000);
write(this->descriptor,&stx,1);
usleep(100000);
ret = write(this->descriptor,bytes,132);
usleep(100000);
write(this->descriptor,&etx,1);
usleep(100000);
write(this->descriptor,&lrc,1);
qDebug() << "Done";
free(bytes);
}
The data argument is: E11U000008507000099VZ000000
Of course, the documentation is in German, which I don't speak, so this is as far as I have gotten. I've basically got 1 month to implement this then I have to give the device back.
If anyone has any pointers, or some example code that would be awesome.
/jason

The transport protocol looks like something standard, so maybe you should only send len bytes of the data not 132 and include the ETX character in the lrc summing ?
It might be easier and clearer to use QByteArray instead of malloc arrays or QString (QString are for user displayed strings which is not the case here):
void PayLife::sendPayLifeData(const QByteArray & data) {
static const char stx = 0x02;
static const char etx = 0x03;
static const char ack = 0x06;
QByteArray buffer = stx + data + etx;
// Calculate the xor sum on data + etx
char lrc = 0;
for(int i = 1; i < buffer.size(); ++i) {
lrc ^= buffer[i];
}
buffer += lrc;
qDebug() << "Starting";
write(this->descriptor, &ack, 1);
write(this->descriptor, buffer.data(), buffer.size());
qDebug() << "Done";
}
You should also have a look at QSerialDevice, it could allow you to implement the protocol in a more event driven way with signal and slots.

Related

Strange behaviour when sending messages from c++ to chromium extension [Native Messaging] - No data being sent

Hi and hope everyone is doing good!
I started working on a chrome extension which talks to a cpp exe. At the moment I am just trying to read some data from the extension which works as expected using the following code
unsigned int length = 0;
{
unsigned int read_char = getchar();
length = length | (read_char << index*8);
}
std::string message = "";
for (int index = 0; index < length; index++)
{
message += getchar();
}
When trying to send the same information from the cpp -> extension using the following code
unsigned int len = message.length();
printf("%c%c%c%c", (char) (len & 0xff),
(char) (len << 8 & 0xff),
(char) (len << 16 & 0xff),
(char) (len << 24 & 0xff));
printf("%s", message.c_str());
it works as expected
Screenshot of the working scenario
However, when i try to send back another string rather than the same string that we send it won't work.
Example:
unsigned int length = 0;
for (int index = 0; index < 4; index++)
{
unsigned int read_char = getchar();
cerr << read_char << endl;
length = length | (read_char << index*8);
}
std::string message = "";
for (int index = 0; index < length; index++)
{
message += getchar();
}
std::string outputMessage = "output";
unsigned int len = outputMessage.length();
printf("%c%c%c%c", (char) (len & 0xff),
(char) (len << 8 & 0xff),
(char) (len << 16 & 0xff),
(char) (len << 24 & 0xff));
printf("%s", outputMessage.c_str());
return 0;
Here is also the screenshot of the scenario that is failing. Failed scenario
I am not sure what I missed here, consider that I am just creating a new string and also using it's length for information that the extension needs.
Anyway, it would be great if anyone could look at this one. Thanks in advance :)
UPDATE:
After trying different ways of returning messages I found this on the web and it works as expected
message_t encode_message(json content) {
string encoded_content = content.dump();
message_t m;
m.content = encoded_content;
m.length = (uint32_t)encoded_content.length();
return m;
}
// Send an encoded message to stdout.
void send_message(message_t encoded_message) {
char* raw_length = reinterpret_cast<char*>(&encoded_message.length);
fwrite(raw_length, 4, sizeof(char), stdout);
fwrite(encoded_message.content.c_str(), encoded_message.length, sizeof(char), stdout);
fflush(stdout);
}
You have to explicitly flush the buffer, if those data are to be sent to the native messaging host ASAP as shown below:
std::string outputMessage = "output";
unsigned int len = outputMessage.length();
printf("%c%c%c%c", (char) (len & 0xff),
(char) ((len >> 8) & 0xff),
(char) ((len >> 16) & 0xff),
(char) ((len >> 24) & 0xff));
printf("%s", outputMessage.c_str());
fflush(stdout); // This will flush the buffer

Socket Communication Data Corruption on Write/Read

I've got a C++ server that communicates with multiple clients. It uses a vector to store the handles to the sockets for those clients (playerSockets in the code below). At the end of the "game" I want the server to loop through that vector and write the same string to each client. However, sometimes the data that the client reads (and then displays) is "corrupted" as you can see in the screenshot, but this doesn't happen for the first client, only the second. I can't figure out why this is happening! I use this same technique (looping and writing) earlier in the program and it always works fine in that instance.
Here is what it is supposed to be shown:
Here and here's what I get:
Here is the server code that writes:
std::string announcement = "";
if (playerWon) {
...
}
} else {
announcement = "?No one won the game!\nGAME BOARD: " + cn.getGameBoard();
for (int player : gameData->playerSockets) {
write(player, announcement.c_str(), announcement.size() + 1);
}
}
And here's the client code that reads. Keep in mind that more than one client is running and connected to the server, and this issue only happens with a client OTHER THAN the first client in the server's loop:
static bool readMyTurn(int clientSd) {
...
char buf[BUFSIZE];
read(clientSd, buf, BUFSIZE);
string myTurn(buf);
cout << "MYMYMYMY: " << myTurn << endl;
myTurn.erase(0, 1);
cout << myTurn << endl;
...
}
UPDATE
Here is my current code to read until encountering the null-terminator character.
string readOneStringFromServer(int clientSd, string &leftovers) {
ssize_t nullTerminatorPosition = 0;
std::string stringToReturn = "";
do {
char buf[BUFSIZE];
ssize_t bytesRead = read(clientSd, buf, BUFSIZE);
nullTerminatorPosition = findPositionOfNullTerminator(buf, bytesRead);
// found a null terminator
if (nullTerminatorPosition != -1) {
// create a buffer to hold all of the chars from buf1 up to and including the null terminator
char upToNullTerminator[nullTerminatorPosition + 1];
// get those chars from buf1 and put them into buf2 (including the null terminator)
for (int i = 0; i < nullTerminatorPosition + 1; ++i) {
upToNullTerminator[i] = buf[i];
}
// use buf2 to create a string
stringToReturn += upToNullTerminator;
// check if there are leftover bytes after the null terminator
int leftoverBytes = bytesRead - nullTerminatorPosition - 1;
if (leftoverBytes != 0) {
// if there are, create a char array of that size
char leftoverChars[leftoverBytes];
// loop through buf1 and add the leftover chars to buf3
for (int i = nullTerminatorPosition + 1; i < bytesRead; ++i) {
leftoverChars[i - (nullTerminatorPosition + 1)] = buf[i];
}
// make a string out of those leftover chars
leftovers = leftoverChars;
} else {
// if there are no leftover bytes, then we want to "erase" what is currently held in leftovers so that
// it doesn't get passed to the next function call
leftovers = "";
}
// didn't find one
} else {
stringToReturn += buf;
}
} while (nullTerminatorPosition == -1);
return stringToReturn;
}

RTMP Broadcast packet body structure for Twitch

I'm currently working on a project similar to OBS, where I'm capturing screen data, encoding it with the x264 library, and then broadcasting it to a twitch server.
Currently, the servers are accepting the data, but no video is being played - it buffers for a moment, then returns an error code "2000: network error"
Like OBS Classic, I'm dividing each NAL provided by x264 by its type, and then making changes to each
int frame_size = x264_encoder_encode(encoder, &nals, &num_nals, &pic_in, &pic_out);
//sort the NAL's into their types and make necessary adjustments
int timeOffset = int(pic_out.i_pts - pic_out.i_dts);
timeOffset = htonl(timeOffset);//host to network translation, ensure the bytes are in the right format
BYTE *timeOffsetAddr = ((BYTE*)&timeOffset) + 1;
videoSection sect;
bool foundFrame = false;
uint8_t * spsPayload = NULL;
int spsSize = 0;
for (int i = 0; i<num_nals; i++) {
//std::cout << "VideoEncoder: EncodedImages Size: " << encodedImages->size() << std::endl;
x264_nal_t &nal = nals[i];
//std::cout << "NAL is:" << nal.i_type << std::endl;
//need to account for pps/sps, seems to always be the first frame sent
if (nal.i_type == NAL_SPS) {
spsSize = nal.i_payload;
spsPayload = (uint8_t*)malloc(spsSize);
memcpy(spsPayload, nal.p_payload, spsSize);
} else if (nal.i_type == NAL_PPS){
//pps always happens after sps
if (spsPayload == NULL) {
std::cout << "VideoEncoder: critical error, sps not set" << std::endl;
}
uint8_t * payload = (uint8_t*)malloc(nal.i_payload + spsSize);
memcpy(payload, spsPayload, spsSize);
memcpy(payload, nal.p_payload + spsSize, nal.i_payload);
sect = { nal.i_payload + spsSize, payload, nal.i_type };
encodedImages->push(sect);
} else if (nal.i_type == NAL_SEI || nal.i_type == NAL_FILLER) {
//these need some bytes at the start removed
BYTE *skip = nal.p_payload;
while (*(skip++) != 0x1);
int skipBytes = (int)(skip - nal.p_payload);
int newPayloadSize = (nal.i_payload - skipBytes);
uint8_t * payload = (uint8_t*)malloc(newPayloadSize);
memcpy(payload, nal.p_payload + skipBytes, newPayloadSize);
sect = { newPayloadSize, payload, nal.i_type };
encodedImages->push(sect);
} else if (nal.i_type == NAL_SLICE_IDR || nal.i_type == NAL_SLICE) {
//these packets need an additional section at the start
BYTE *skip = nal.p_payload;
while (*(skip++) != 0x1);
int skipBytes = (int)(skip - nal.p_payload);
std::vector<BYTE> bodyData;
if (!foundFrame) {
if (nal.i_type == NAL_SLICE_IDR) { bodyData.push_back(0x17); } else { bodyData.push_back(0x27); } //add a 17 or a 27 as appropriate
bodyData.push_back(1);
bodyData.push_back(*timeOffsetAddr);
foundFrame = true;
}
//put into the payload the bodyData followed by the nal payload
uint8_t * bodyDataPayload = (uint8_t*)malloc(bodyData.size());
memcpy(bodyDataPayload, bodyData.data(), bodyData.size() * sizeof(BYTE));
int newPayloadSize = (nal.i_payload - skipBytes);
uint8_t * payload = (uint8_t*)malloc(newPayloadSize + sizeof(bodyDataPayload));
memcpy(payload, bodyDataPayload, sizeof(bodyDataPayload));
memcpy(payload + sizeof(bodyDataPayload), nal.p_payload + skipBytes, newPayloadSize);
int totalSize = newPayloadSize + sizeof(bodyDataPayload);
sect = { totalSize, payload, nal.i_type };
encodedImages->push(sect);
} else {
std::cout << "VideoEncoder: Nal type did not match expected" << std::endl;
continue;
}
}
The NAL payload data is then put into a struct, VideoSection, in a queue buffer
//used to transfer encoded data
struct videoSection {
int frameSize;
uint8_t* payload;
int type;
};
After which it is picked up by the broadcaster, a few more changes are made, and then I call rtmp_send()
videoSection sect = encodedImages->front();
encodedImages->pop();
//std::cout << "Broadcaster: Frame Size: " << sect.frameSize << std::endl;
//two methods of sending RTMP data, _sendpacket and _write. Using sendpacket for greater control
RTMPPacket * packet;
unsigned char* buf = (unsigned char*)sect.payload;
int type = buf[0]&0x1f; //I believe &0x1f sets a 32bit limit
int len = sect.frameSize;
long timeOffset = GetTickCount() - rtmp_start_time;
//assign space packet will need
packet = (RTMPPacket *)malloc(sizeof(RTMPPacket)+RTMP_MAX_HEADER_SIZE + len + 9);
memset(packet, 0, sizeof(RTMPPacket) + RTMP_MAX_HEADER_SIZE);
packet->m_body = (char *)packet + sizeof(RTMPPacket) + RTMP_MAX_HEADER_SIZE;
packet->m_nBodySize = len + 9;
//std::cout << "Broadcaster: Packet Size: " << sizeof(RTMPPacket) + RTMP_MAX_HEADER_SIZE + len + 9 << std::endl;
//std::cout << "Broadcaster: Packet Body Size: " << len + 9 << std::endl;
//set body to point to the packetbody
unsigned char *body = (unsigned char *)packet->m_body;
memset(body, 0, len + 9);
//NAL_SLICE_IDR represents keyframe
//first element determines packet type
body[0] = 0x27;//inter-frame h.264
if (sect.type == NAL_SLICE_IDR) {
body[0] = 0x17; //h.264 codec id
}
//-------------------------------------------------------------------------------
//this section taken from https://stackoverflow.com/questions/25031759/using-x264-and-librtmp-to-send-live-camera-frame-but-the-flash-cant-show
//in an effort to understand packet format. it does not resolve my previous issues formatting the data for twitch to play it
//sets body to be NAL unit
body[1] = 0x01;
body[2] = 0x00;
body[3] = 0x00;
body[4] = 0x00;
//>> is a shift right
//shift len to the right, and AND it
/*body[5] = (len >> 24) & 0xff;
body[6] = (len >> 16) & 0xff;
body[7] = (len >> 8) & 0xff;
body[8] = (len) & 0xff;*/
//end code sourced from https://stackoverflow.com/questions/25031759/using-x264-and-librtmp-to-send-live-camera-frame-but-the-flash-cant-show
//-------------------------------------------------------------------------------
//copy from buffer into rest of body
memcpy(&body[9], buf, len);
//DEBUG
//save individual packet body to a file with name rtmp[packetnum]
//determine why some packets do not have 0x27 or 0x17 at the start
//still happening, makes no sense given the above code
/*std::string fileLocation = "rtmp" + std::to_string(packCount++);
std::cout << fileLocation << std::endl;
const char * charConversion = fileLocation.c_str();
FILE* saveFile = NULL;
saveFile = fopen(charConversion, "w+b");//open as write and binary
if (!fwrite(body, len + 9, 1, saveFile)) {
std::cout << "VideoEncoder: Error while trying to write to file" << std::endl;
}
fclose(saveFile);*/
//END DEBUG
//other packet details
packet->m_hasAbsTimestamp = 0;
packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
if (rtmp != NULL) {
packet->m_nInfoField2 = rtmp->m_stream_id;
}
packet->m_nChannel = 0x04;
packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
packet->m_nTimeStamp = timeOffset;
//send the packet
if (rtmp != NULL) {
RTMP_SendPacket(rtmp, packet, TRUE);
}
I can see that Twitch is receiving the data in the inspector, at a steady 3kbps. so I'm sure something is wrong with how I'm adjusting the data before sending it. Can anyone advise me on what I'm doing wrong here?
The problems start before the code you included even. When you configure x264 be sure to set:
b_aud = 0;
b_repeat_headers = 0;
b_annexb = 0;
This will tell x264 to generate the format needed by rtmp, Then you can skip all the per-nal preprocessing.
For sps/pps use x264_encoder_headers to retrieve them after x264_encoder_open. Encode them into an "extradata" buffer as documented here Possible Locations for Sequence/Picture Parameter Set(s) for H.264 Stream. This extradata goes into an rtmp "sequence header" packet before any frames are sent. Set the frame the AVCPacketType accordingly body[1] in your case, 0 for sequence header 1 for everything else,
body[0] = 0x27;
body[1] = 0;
body[2] = 0;
body[3] = 0;
body[4] = 0;
memcpy(&body[5], extradata, extradata_size);
body[2] through body[4] MUST be set to the frame cts (pts - dts) if you have b frames. If you want to set it to zero, configure x264 for baseline profile, but this will result in reduced image quality. Use the return code from x264_encoder_encode as the frame size, and write the whole frame in one go.
int frame_size = x264_encoder_encode(encoder, &nals, &num_nals, &pic_in, &pic_out);
if(frame_size) {
int cts = pic_out->i_pts - pic_out->i_dts;
body[0] = pic_out->b_keyframe ? 0x27 : 0x17;
body[1] = 1;
body[2] = cts>>16;
body[3] = cts>>8;
body[4] = cts;
memcpy(&body[5], nals->p_payload, frame_size);
}
Finally, Twitch requires you also send an AAC audio stream. and be sure to set the keyframe interval to 2 seconds.

Google Protocol Buffers: parseDelimitedFrom and writeDelimitedTo for C++

Sorry to ask this again, but could we please once and for all post some C++ functions that match the Java ones here? They don't seem to be getting added by google, and it is a quite a pain to write them yourself. Below answer using some of this and this.
Here are the two basic versions with boost asio. Notice that to make this work properly, technically, in the second version, one would need to look at how much data is in the buffer, work out how big the header was (VarInt is not a fixed size), but CodedInputStream has GetDirectBufferPointer, with a pointer to where it is, so from this pointer one could work out the remaining message size, compare it with the given message size, construct a new adjusted buffer for the remaining size, and do a asio synchronous read for the rest of the message. Below works as long as messages remain small (I guess around 1 kb or so). If someone has the missing bit, please speak up. Thanks.
writeDelimitedTo in C++:
boost::asio::streambuf request;
{
std::ostream request_stream(&request);
google::protobuf::io::OstreamOutputStream raw_output (&request_stream);
google::protobuf::io::CodedOutputStream coded_output(&raw_output);
coded_output.WriteVarint32(myProtoMsg.ByteSize());
myProtoMsg.SerializeToCodedStream(&coded_output);
}
boost::asio::write(socket,request);
parseDelimitedFrom:
char buf[5000];
void Session::Read()
{
boost::asio::async_read(
socket,
boost::asio::buffer(buf),
boost::asio::transfer_at_least(1),
boost::bind(&Session::Handle_Read,shared_from_this(),boost::asio::placeholders::error));
}
void Session::Handle_Read(const boost::system::error_code& error)
{
if (!error)
{
google::protobuf::io::ArrayInputStream arrayInputStream(buf,5000);
google::protobuf::io::CodedInputStream codedInputStream(&arrayInputStream);
uint32_t messageSize;
codedInputStream.ReadVarint32(&messageSize);
//Read more here
MyProtoMsg myProtoMsg;
myProtoMsg.ParseFromCodedStream(&codedInputStream);
}
Read();
}
EDIT: Above is a bit lazy (with "read more here"). Below is a complete parseDelimitedFrom. Any comments welcome.
NEW parseDelimitedFrom:
static void ReadMyVarint32(int& headerSize,int& messageSize,char buffer[])
{
// Fast path: We have enough bytes left in the buffer to guarantee that
// this read won't cross the end, so we can skip the checks.
char const* ptr = buffer;
char b;
uint32_t result;
b = *(ptr++); result = (b & 0x7F) ; if (!(b & 0x80)) goto done;
b = *(ptr++); result |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
b = *(ptr++); result |= b << 28; if (!(b & 0x80)) goto done;
// If the input is larger than 32 bits, we still need to read it all
// and discard the high-order bits.
for (int i = 0; i < 5; i++) {
b = *(ptr++); if (!(b & 0x80)) goto done;
}
// We have overrun the maximum size of a varint (10 bytes). Assume
// the data is corrupt.
headerSize = 0;
messageSize = 0;
done:
headerSize = ptr - buffer;
messageSize = (int)result;
}
char buf[5000];
int receivedSize(0);
int missingSize(0);
void Session::Read()
{
boost::asio::async_read(
socket,
boost::asio::buffer(buf),
boost::asio::transfer_at_least(1),
boost::bind(&Session::Handle_Read,shared_from_this(),_1,_2));
}
void Session::Handle_Read(const boost::system::error_code& error,std::size_t bytes_transferred)
{
if (!error)
{
int mybytes_transferred((int)bytes_transferred);
if(missingSize == 0)
{
int headerSize, messageSize;
ReadMyVarint32(headerSize,messageSize,buf);
//std::cout << "Read new message: HeaderSize " << headerSize << " MessageSize " << messageSize << " Received: " << mybytes_transferred << std::endl;
for(int i(0);i<mybytes_transferred-headerSize;++i)
request[i] = buf[headerSize+i];
missingSize = headerSize + messageSize - mybytes_transferred;
receivedSize = mybytes_transferred - headerSize;
}
else
{
//std::cout << "Continue message: Read so far " << receivedSize << " Missing " << missingSize << " Received: " << mybytes_transferred << std::endl;
for(int i(0);i<mybytes_transferred;++i)
request[receivedSize+i] = buf[i];
missingSize -= mybytes_transferred;
receivedSize += mybytes_transferred;
}
if(missingSize < 0)
{
//Received too much, give up
missingSize = 0;
receivedSize = 0;
}
else if(missingSize == 0)
{
// Use your proto class here
RequestWrapperPtr requestWrapperPtr(new RequestWrapper());
if(requestWrapperPtr->ParseFromArray(request,receivedSize))
{
HandleRW(requestWrapperPtr);
}
else
{
// std::cout << BaseString() << "Session Handle_Read: Failed to parse!";
}
}
Read();
}
}
I know this question has been answered, but the question is super old now, and updates have been made to the protobuf code repository since then.
Protobuf now has these functions under the header file here:
#include <google/protobuf/util/delimited_message_util.h>
You can check out the associated cpp file on the git repo here.
I have tried out the functions with a boost socket and they work as expected.

unix domain stream sockets sending more data then it should be

I have two simple programs set up that share data through a unix domain socket. One program reads data out of a Queue and sends it to the other application. Before it is sent each piece of data is front-appended by four bytes with the length, if it is less then four bytes the left over bytes are the '^' symbol.
The client application then reads the first four bytes, sets a buffer to the appropriate size and then reads the rest. The problem that I'm having is that the first time through the message will be sent perfectly. Every other time after that there is extra data being sent so a message like "what a nice day out" would come out like "what a nice day out??X??". So I feel like a buffer is not being cleared correctly but I can't seem to find it.
Client code:
listen(sock, 5);
for (;;)
{
msgsock = accept(sock, 0, 0);
if (msgsock == -1)
perror("accept");
else do
{
char buf[4];
bzero(buf, sizeof(buf));
if ((rval = read(msgsock, buf, 4)) < 0)
perror("reading stream message");
printf("--!%s\n", buf);
string temp = buf;
int pos = temp.find("^");
if(pos != string::npos)
{
temp = temp.substr(0, pos);
}
int sizeOfString = atoi(temp.c_str());
cout << "TEMP STRING: " << temp << endl;
cout << "LENGTH " << sizeOfString << endl;
char feedWord[sizeOfString];
bzero(feedWord, sizeof(feedWord));
if ((rval = read(msgsock, feedWord, sizeOfString)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", feedWord);
bzero(feedWord, sizeof(feedWord));
sizeOfString = 0;
temp.clear();
}
while (rval > 0);
close(msgsock);
}
close(sock);
unlink(NAME);
Server Code
pthread_mutex_lock(&mylock);
string s;
s.clear();
s = dataQueue.front();
dataQueue.pop();
pthread_mutex_unlock(&mylock);
int sizeOfString = strlen(s.c_str());
char sizeofStringBuffer[10];
sprintf(sizeofStringBuffer, "%i", sizeOfString);
string actualString = sizeofStringBuffer;
int tempSize = strlen(sizeofStringBuffer);
int remainder = 4 - tempSize;
int x;
for(x =0; x < remainder; x++)
{
actualString = actualString + "^";
}
cout << "LENGTH OF ACTUAL STRING: " << sizeOfString << endl;
actualString = actualString + s;
cout << "************************" << actualString << endl;
int length = strlen(actualString.c_str());
char finalString[length];
bzero(finalString, sizeof(finalString));
strcpy(finalString, actualString.c_str());
if (write(sock, finalString, length) < 0)
perror("writing on stream socket");
Rather than padding your packet length with '^', you'd be far better off just doing:
snprintf(sizeofStringBuffer, 5, "%04d", sizeOfString);
so that the value is 0 padded - then you don't need to parse out the '^' characters in the receiver code.
Please also edit out your debug code - there's only one write() in the current code, and it doesn't match your description of the protocol.
Ideally - split your sending routine into a function of its own. You can also take advantage of writev() to handle coalescing the string holding the "length" field with the buffer holding the actual data and then sending them as a single atomic write().
Untested code follows:
int write_message(int s, std::string msg)
{
struct iovec iov[2];
char hdr[5];
char *cmsg = msg.c_str();
int len = msg.length();
snprintf(hdr, 5, "%04d", len); // nb: assumes len <= 9999;
iov[0].iov_base = hdr;
iov[0].iov_len = 4;
iov[1].iov_base = cmsg;
iov[1].iov_len = len;
return writev(s, iov, 2);
}
You have to check return values of both write and read not only for -1 but for short (less then requested) writes/reads. You also seem to just continue after printing an error with perror - do an exit(2) or something there.
Two things:
First - on the Server side you are writing off the end of your array.
char finalString[length];
bzero(finalString, sizeof(finalString));
strcpy(finalString, actualString.c_str());
The strcpy() will copy length+1 characters into finalString (character pull the null terminator).
Second (and most likely to be the problem) - on the client side you are not null terminating the string you read in, therefore the printf() will print your string, and then whatever is on the stack up to the point it hits a null.
Increase both buffers by one, and you should be in better shape.