I have some code where in, there is a TCP connection between the client and the server. I need to send some xml data to the server and receive a response from it. I am trying to do it like this:
char request[MAX];
sprintf(request, "<attestationRequest><majorVersion>%d</majorVersion><minorVersion>%d</minorVersion></attestationRequest>", major, minor);
write(sockfd,request, length);
while(recv(sockfd, response, MAX, 0) >= 0)
{
cout << "response " << response;
//do something;
}
But the data received is (expected response + request).
If I try to fill the data using QString, the data received is proper.
QString request = QString("<attestationRequest>"
"<majorVersion>%1</majorVersion>"
"<minorVersion>%2</minorVersion>"
"</attestationRequest>")
.arg(major)
.arg(minor)
The rest of the code is same for both the cases. I receive more than 11000 bytes of data when I use sprintf, but 9000 bytes in case of QString. I am not able to understand if I am missing something.
IMO both solution are bad.
It is safer and better to use QXmlStreamWriter. Manual manipulation on text will in most cases end with incorrect encoding or missing escape sequence or other xml format violation.
Other problem is that you didn't gave any data how you perform communication. It is highly probable that there is an error causing your problem.
Most likely your problem is, that UTF-16 data is sent through the connection (that is QString.)
Maybe if you tried the w_char-versions of those commands, it might succeed.
Related
I am writing a server-client application using Winsock in c++ for sending a file line by line and I have a problem in sending huge string. The line size is very huge.
For getting the message from the client by the server I use the code below.
int result;
char message[200];
while (true)
{
recv(newSd, (char*)&message, sizeof(message), 0);
cout << "The Message from client: " << message << ";";
}
The above code working fine if I send small length of the message. But, what I wanted is to send an unknown size of lines in a file.
How to send a big unknown string instead of char message[200];
TCP is a byte stream, it knows nothing about messages or lines or anything like that. When you send data over TCP, all it knows about is raw bytes, not what the bytes represent. It is your responsibility to implement a messaging protocol on top of TCP to delimit the data in some meaningful way so the receiver can know when the data is complete. There are two ways to do that:
send the data length before sending the actual data. The receiver reads the length first, then reads however many bytes the length says.
send a unique terminator after sending the data. Make sure the terminator never appears in the data. The receiver can then read until the terminator is received.
You are not handling either of those in your recv() code, so I suspect you are not handling either of them in your send() code, too (which you did not show).
Since you are sending a text file, you can either:
send the file size, such as in a uint32_t or uint64_t (depending on how large the file is), then send the raw file bytes.
send each text line individually as-is, terminated by a CRLF or bare-LF line break after each line, and then send a final terminator after the last line.
You are also ignoring the return value of recv(), which tells you how many bytes were actually received. It can, and usually does, return fewer bytes than requested, so you must be prepared to call recv() multiple times, usually in a loop, to receive data completely. Same with send().
I got simple server-client app.
The idia is:
Client send to server string with sql-request.
Server process the request and send back on client answer with data formated in csv style string.
Everything is already adjusted accept one thing. The problem is to read answer on client cause I don't know the size of recieved string.
Code is bellow:
Server:
std::string answer;
answer = sql_read(*msg); //get the string with data from request
clientSock->write_some(buffer(answer, answer.size())); //send it back on client
Client:
std::string answer;
bytesRead = sock->read_some(boost::asio::buffer(readBuf, inputSize)); //read the answer, but how do I know correct size of string?
string_ptr msg(new std::string(readBuf, bytesRead));
answer = *msg;
How to read the resulting string without knowing its size?
Or if my aproach (with sending data in string) is radically wrong how to do it in correct way?
You must handle this yourself in the protocol the client and server use to speak to each other.
One way is to use a deliminator and use boost::asio::read_until(). Example:
boost::asio::streambuf buf;
boost::asio::read_until (sock, buf, "\r\n"); // or '\0' if zero terminated
Check the Boost.Asio documentation.
Another way is to send the size in an fixed length header before sending the variable length part.
You won't know the size of the string in advance. Where you do the read_some you will need to do a loop to read all the data from the socket. You need to check the number of bytes read and the size of the buffer you allocated. If they are equal then you filled up your read buffer and you need to do another read to check for any remaining data.
i am trying to send data via tcp socket to a server. The idea behind that is a really simple chat programm.
The string I am trying to send looks like the following:
1:2:e9e633097ab9ceb3e48ec3f70ee2beba41d05d5420efee5da85f97d97005727587fda33ef4ff2322088f4c79e8133cc9cd9f3512f4d3a303cbdb5bc585415a00:2:xc_[z kxc_[z kxc_[z kxc_[==
As you can see there a few unprintable characters which I don't think are a problem here.
To send this data I am using the following code snippet.
bool tcp_client::send_data(string data)
{
if( send(sock , data.c_str(), strlen(data.c_str()) , 0) < 0)
{
perror("Send failed : ");
return false;
}
return true;
}
After a few minutes of trying things out I came up, that data.c_str() cuts my string of.
The result is:
1:2:e9e633097ab9ceb3e48ec3f70ee2beba41d05d5420efee5da85f97d97005727587fda33ef4ff2322088f4c79e8133cc9cd9f3512f4d3a303cbdb5bc585415a00:2:xc_[z
I think that there is some kind of null sequence inside my string which is a problem for the c_str() function.
Is there a way to send the whole string as I mentioned aboved without cutting it off?
Thanks.
Is there a way to send the whole string as I mentioned aboved without cutting it off?
What about:
send(sock , data.c_str(), data.size() , 0);
There are only two sane ways to send arbitrary data (such as a array of characters) over stream sockets:
On the server: close the socket after data was sent (like in ftp, http 0.9, etc). On the client - read until socket is closed in a loop.
On the server: prefix the data with fixed-length size (nowadays people usualy use 64 bit integers for size, watch out for endiannes). On the client - read the size first (in a loop!), than read the data until size bytes are read (in a loop).
Everything else is going to backfire sooner or later.
I'm having hard time understanding how to work with 0MZ properly. When I'm trying to send a message initialized with size larger than 29, something goes wrong. My code is very simple:
zmq::context_t context (1);
zmq::socket_t req(context,ZMQ_REQ);
req.connect("tcp://localhost:6969");
int msgSize = 100;
zmq::message_t test(msgSize);
snprintf((char*)test.data(),msgSize,"short message");
cout << static_cast<char*>(test.data())<< endl; // this is always fine - 'short message'
so far so good, but after sending this message, if msgSize>29, i can't get the same result again
req.send(test);
cout << static_cast<char*>(test.data())<< endl; // now it's gibberish, like '&?+#'
what's even more puzzling, if my server receives the message it also looks like '&?+#' there, but if it is sending it back simply with PUB socket, I can read it again in my client:
zmq::message_t reply;
req.recv(&reply);
cout << static_cast<char*>(test.data())<< endl; - 'my message' again!
I understand, that there is some 29 bytes limit on short messages, but how can i get around it, without dealing with multipart messages? I literally need like 40 chars....
If the message is > 30 bytes, the memory once occupied by 'test', but then freed, must be being reused by the reply data (obviously by serendipity). Thus, when you look at 'test' again it magically appears to be what you think it should be. This theory should be very simple for you to verify in the debugger by looking at addresses.
Whatever, as Hristo said, sending a message frees it's original contents and shouldn't be used again.
ZeroMQ has an optimisation for small messages where the payload doesn't need to be separately allocated. Again, the fact that you can still see the contents you expect after sending a message is just an artefact; you cannot rely on it.
If you have a requirement to retain the contents of messages after they're sent, take a look at zmq_send_const(), which is new with ZMQ 4.0. I don't know if any bindings make use of it.
As it turned out, I had an error generating piece of code within my server app, after receiving a message I did instant ping pong style reply, like:
zmq::message_t msg(msgSize);
REC.recv(&msg);
//pong
REC.send(msg);
And as above answer points out, sending a message frees it's original contents, leaving me with unwanted gibberish of random bytes.
Now the server (implemented with java) will send some stream data to me, my code is like below:
connect(socket, SIGNAL(readyRead()), this, SLOT(read_from_server()));
in the read_from_server():
{
while (socket->bytesAvailable())
{
QString temp = socket->readAll();
}
}
but I find that even the server sent me a string with only several characters, the data is truncated, and my function is called twice, thus temp is the never complete data that I want.
If server send me a longer string, my function may be called three or more times, making me diffficult to know at which time the data is transfered completely.
So anyone can tell me how to completely receive the data easily, without so many steps of bothering? I'm sorry if this is duplicated with some questions else, I couldn't get their answers work for me. Many thanks!
What you're seeing is normal for client-server communication. Data is sent in packets and the readyRead signal is informing your program that there is data available, but has no concept of what or how much data there is, so you have to handle this.
To read the data correctly, you will need a buffer, as mentioned by #ratchetfreak, to append the bytes as they're read from the stream. It is important that you know the format of the data being sent, in order to know when you have a complete message. I have previously used at least two methods to do this: -
1) Ensure that sent messages begin with the size, in bytes, of the message being sent. On receiving data, you start by reading the size and keep appending to your buffer until it totals the size to expect.
2) Send all data in a known format, such as JSON or XML, which can be checked for the end of the message. For example, in the case of JSON, all packets will begin with an opening brace '{' and end with a closing brace '}', so you could count braces and match up the data, or use QJsonDocument::fromRawData to verify that the data is complete.
Having used both of these methods, I recommend using the first; include the size of a message that is being sent.
you can use a buffer field to hold the unfinished data temporarily and handle packets as they complete:
{
while (socket->bytesAvailable())
{
buffer.append(socket->readAll());
int packetSize = getPacketSize(buffer);
while(packetSize>0)
{
handlePacket(buffer.left(packetSize);
buffer.remove(0,packetSize);
packetSize = getPacketSize(buffer);
}
}
}
If all of the data has not yet arrived then your while loop will exit prematurely. You need to use a message format that will let the receiving code determine when the complete message has been received. For example, the message could begin with a length element, or if you are dealing with text the message could end with some character used as a terminator.
Problem is that during tcp data transfer data are send in undefined chunks. If you are trying to read defined block size you have to know in advance expected chunk size ore have a way to determinate when your block ends (something like zero terminated c-string).
Check if this answer doesn't help you (there is a trick to wait for expected data block).