I'm having issues with receiving a transfer.
QTcpSocket->readAll() does not read enough bytes when I'm sending to it. When I send 15k bytes, it reads only some part of it and then does nothing. What am I doing wrong?
QByteArray array;
array = socket->readAll(); //just reads some part, not fully.
Why does this happen?
Most probably the socket didn't receive all data yet when you call readAll(). This is because of TCP communication happens in small packets (each having around 1KB of data, depending on a lot of things). These packets make up a stream in which the other end of the communication line writes bytes into. You have to assemble them on the receiving side. How you assemble them has to be defined in a protocol.
To solve this issue, you have to wait for all expected data before assembling it. Sometimes it is not known how much data is expected unless you read it (depending on the protocol).
Let's say you want to implement a protocol which says "everything until a line break is something we call a message". Now you want to receive such a message. This is done by successively reading and appending to a target buffer (like your QByteArray) until there comes a line break. However, there is another thing: When you expect a second message, it can be immediately after the first one in the TCP stream, so you just read not only the end of the first message, but also the beginning of the second. Just keep this in mind.
When not dealing with signal slot connection, you can write a synchronous receiver for such newline-separated messages like this:
QByteArray array;
while(!array.contains('\n')) {
socket->waitForReadyRead();
array += socket->readAll();
}
int bytes = array.indexOf('\n') + 1; // Find the end of message
QByteArray message = array.left(bytes); // Cut the message
array = array.mid(bytes); // Keep the data read too early
processMessage(message);
When handling QTcpSocket::readyRead(), you can do something similar.
void MyClass::socketReadyRead() // connected to QTcpSocket::readyRead() signal
{
array += socket->readAll();
if(array.contains('\n')) {
int bytes = array.indexOf('\n') + 1; // Find the end of message
QByteArray message = array.left(bytes); // Cut the message
array = array.mid(bytes); // Keep the data read too early
processMessage(message);
socketReadyRead(); // re-call myself to process more
}
}
When you want to read everything sent via one TCP connection (until it gets closed by the peer), you can wait for this event either in a blocking way or process the data in a slot connected to the proper signal: QTcpSocket::disconnected.
Blocking:
socket->waitForDisconnected();
QByteArray array = socket->readAll();
Non-blocking (handling signals using slots):
void MyClass::socketReadyRead() // connected to QTcpSocket::readyRead() signal
{
array += socket->readAll();
// Do NOT process yet!
}
void MyClass::socketDisconnected() // connected to QTcpSocket::disconnected() signal
{
processMessage(array);
}
Alternative non-blocking solution (essentially the same):
// You don't have to connect to QTcpSocket::readyRead() signal in this case
void MyClass::socketDisconnected()
{
processMessage(socket->readAll());
}
Related
I'm writing a C++ program. I need to receive a file and I'm using recv() function over a TCP socket to do that.
download_file() {
while (left_bytes != 0 && !connection_closed) {
if (left_bytes >= buffer_max_size)
bytes_to_download = buffer_max_size;
else
bytes_to_download = left_bytes;
if (request.conn->read_data(buffer, bytes_to_download))
{
left_bytes -= buffer->get_size();
temporary_file.write_data(buffer);
} else connection_closed = true;
}
}
read_data() {
while (bytes_received < size && alive_) {
bytes_read = recv(sock_, read_buffer, size, 0);
if (bytes_read == SOCKET_ERROR) {
delete[] local_buffer;
throw SocketException(WSAGetLastError());
}
// the connection is closed
if (bytes_read == 0) alive_ = false;
else {
bytes_received += bytes_read;
buffer->add(local_buffer, bytes_read);
}
}
}
The problem is that the recv never returns. It receives the whole file except for few KB and it freeze on the recv(). The buffer size is 1460.
I receive the file only if I print something to the console with cout every time the recv is called. Only in this case I receive the whole file.
Otherwise if I set as socket option the WAITALL and the client closes the connection after the file is sent, I receive the whole file.
Here's the code for the Client side that sends the file:
TransmitFile(file_request->connection_->get_handle_socket(), file_handler.get_file_handle(), file_request->file_size_, 65535, nullptr, nullptr, TF_USE_SYSTEM_THREAD)
EDIT
Here's how I send and read the file size between the Client and Server.
std::stringstream stream_;
stream_.str(std::string());
// append the file size
const __int64 file_size = htonll(GetFileSize(file_handle_, nullptr););
stream_ << ' ' << file_size << ' ';
Then I use the send to send this string
Here's how I read the file size
// Within stream_ there is all the content of the received packet
std::string message;
std::getline(stream_, message, ' ');
this->request_body_.file_size_ = ntohll(strtoll(message.c_str(), nullptr, 0));
EDIT
I cleaned up the code and I found out that read_data() is obviously called once and I was updating the buffer variable wrongly. Hence I was tracking the size of the content within the buffer in a wrong way which make me call the recv() once more.
First thing: recv() will block if there are no bytes left to read but the connection is still open. So whatever you might say about what your code is doing, that must be what is happening here.
That could be for any of the following reasons:
the sender lied about the size of the file, or did not send the promised number of bytes
the file size was not interpreted correctly at the receiving end for whatever reason
the logic that 'counts down' the number of bytes left in the receiver is somehow flawed
Trouble is, looking at the code samples you have posted, it's hard to say which because the code is a bit muddled and, in my eyes, more complicated than it needs to be. I'm going to recommend you sort that out.
Sending the size of the file.
Don't mess about sending this as a string. Send it instead in binary, using (say) htonll() at the sending end and ntohll() at the receiving end. Then, the receiver knows to read exactly 8 bytes to figure out what's coming next. It's hard to get that wrong.
Sending the file itself.
TransmitFile() looks to be a good choice here. Stick with it.
Receiving the file and counting down how many bytes are left.
Take a closer look at that code and consider rewriting it. It's a bit of a mess.
What to do if it still doesn't work.
Check with WireShark that the expected data is being sent and then walk through the code in the receiver in the debugger. There is absolutely no excuse for not doing this unless you don't have a debugger for some reason, in which case please say so and somebody will try to help you. The fact that logging to cout fixes your problems is a red-herring. That just changes the timing and then it just happens to work right.
That's all. Best of luck.
I'm aware of the need to call send() in a loop until the desired amount of bytes have been sent. Also on the receiving side.
Here is a part of wrapper around recv I wrote:
do{
result = socket->receiveData(m_recvBuf + recv_len , BUF_LENGTH - recv_len);
recv_len += result;
.....
I'm a little confused about couple of things, so here goes:
if the send() returns 10 bytes, are those ten bytes still only at the sender side, but ready to be sent. Or have the bytes physically arrived to the receiver computer?
If the answer to the above is yes, does then calling recv() always return those 10 bytes as they have already arrived?
I could also put it this way; if send has been called three times each time returning 10, so total bytes sent supposedly being 30. Does then calling recv(), one time, return 30 bytes?
Question 1. edited as "still only at the receiver side" should be "still only at the sender side".
Scenario:
My program in pc1 calls send();
send() returns 1;
My code things that one byte has been sent to the receiver program in pc2.
The network cable got eaten by a dog the moment after my send() function returned 1.
If that is the case in real life, I surely have misunderstood the benefits of TCP vs UDP.
Thanks all for giving time in answering.
I'll try:
You don't know. All that is known is that the network stack has accepted the data, and will do its best to transfer it.
N/A
No, there are no such guarantees. TCP/IP is stream-oriented, it's two streams of bytes with no further structure (messages, packets, writes, frames, whatever). You must make sure your data serialization format supports finding the message boundaries so the receiver can interpret the data.
if send() returns x bytes, does recv() get the same amount of bytes in one call?
In general, certainly no !!
For example, for TCP/IP sockets (see tcp(7) & socket(7)) going through wifi routers and/or intercontinental routers, packets could be fragmented and/or reassembled. So a given send can correspond to several recv and vice versa, and the "boundaries" of messages are not respected. Hence, for applications, TCP is a stream of bytes without any message boundaries. Read also about sliding window protocol and TCP congestiion control used inside TCP.
In practice, you might observe, e.g. between two computers on the same Ethernet cable, that packets are not fragmented or reassembled. But you should not code with that hypothesis.
Concretely, application level protocols like HTTP or SMTP or JSONRPC or X11 protocols should be designed to define message boundaries and both server and client sides should do buffering.
You'll want to use poll(2), see this answer.
if the send() returns 10 bytes, are those ten bytes still only at the receiver side, but ready to be sent.
It is not easy to define what "being still at the reciever side" really means (because you don't really care about what happens inside the kernel, or inside the network controller, or on intercontinental cables). Therefore the above sentence is meaningless.
Your application code should only care about system calls (listed in syscalls(2)...) like poll(2), send(2) and related, write(2), recv(2) and related, read(2), socket(2), accept(2), connect(2), bind(2) etc...
You might want to use messaging libraries like 0mq.
The network cable got eaten by a dog the moment after my send() function returned 1.
Why do you care that much about such a scenario. Your dog could also have dropen your laptop, or have pee-ed on it. Once send has told your application than ten bytes have been emitted, you should trust your kernel. But the receiving program might not yet have gotten these bytes (on another continent, you'll need to wait dozens of milliseconds, which is a quite big delay for a computer). Very probably, the ten bytes are in the middle of the ocean when your dog have bitten your Ethernet cable (and you can reasonably code as if they have been emitted).
The TCP protocol will detect that the link has been interrupted, but that error would be given to your program much later (perhaps as an error for the next call to send happening ten seconds after).
(there are some large macroscopic delays in the TCP definition, perhaps as large as 128 seconds -I forgot the details- and these delays are too small for interplanetary communication; so TCP can't be used to Mars)
You should (most of the time) simply reason at the system call level.
(of course, in some cases -think of remote neurosurgical robots- that might not be enough)
I surely have misunderstood the benefits of TCP vs UDP.
If you just used UDP, a given packet could be fragmented, lost or received several times. With TCP, that cannot reasonably happen (at least when the next packets have been successfully sent and received).
if the send() returns 10 bytes, are those ten bytes still only at the
sender side, but ready to be sent. Or have the bytes physically
arrived to the receiver computer?
You cannot tell where the 10 bytes are exactly, some of them can be waiting somewhere in the sending machine, some over some wire and some waiting somewhere in the receiving machine.
If the answer to the above is yes, does then calling recv() always
return those 10 bytes as they have already arrived?
N/A
I could also put it this way; if send has been called three times each
time returning 10, so total bytes sent supposedly being 30. Does then
calling recv(), one time, return 30 bytes?
You cannot tell! The only thing you can say, in TCP mode, is that bytes are received in the same order that they have being sent.
Scenario: My program in pc1 calls send(); send() returns 1; My code
things that one byte has been sent to the receiver program in pc2. The
network cable got eaten by a dog the moment after my send() function
returned 1.
Then you cannot say anything...
If that is the case in real life, I surely have misunderstood the benefits of TCP vs UDP.
UDP is datagram-oriented semantic, like postal sytem (no preserved order, no guaranty of any kind, loss is possible, duplicate, etc)
TCP is stream-oriented semantic, like phone system (preserved order and no loss).
Of course in case of hard network failure, TCP cannot ensure anything!
As TCP is build on top of IP (datagram) what is sent over TCP is fragmented to be sent via IP, and you don't control such fragmentation (I forgot to tell about caching, etc).
my motto: "if in doubt, try it out".
This is a complete program that demonstrates that on my machine, an entire packet of one million bytes does not even make it through the loopback adapter without being buffered into separate reads (and possibly writes, as I have used the composite function asio::write() :
#include <thread>
#include <mutex>
#include <condition_variable>
#include <boost/asio.hpp>
#include <boost/system/error_code.hpp>
#include <vector>
#include <iostream>
namespace asio
{
using namespace boost::asio;
using boost::system::error_code;
}
using protocol = asio::ip::tcp;
struct event
{
std::mutex mutex;
std::condition_variable cv;
bool notified = false;
void notify()
{
auto lock = std::unique_lock<std::mutex>(mutex);
notified = true;
lock.unlock();
cv.notify_all();
}
void wait()
{
auto lock = std::unique_lock<std::mutex>(mutex);
cv.wait(lock, [this] { return this->notified; });
}
};
struct emitter
{
emitter(std::ostream& os) : os(os) {}
template<class...Ts>
void operator()(Ts&&...ts)
{
auto lock = std::unique_lock<std::mutex>(m);
auto emit_item = [&os = this->os](auto&& x)
{
os << x;
};
using expand = int[];
void(expand { 0,
(emit_item(ts),0)...
});
os << std::endl;
}
std::ostream& os;
std::mutex m;
};
event rx_ready;
emitter stdout_emit { std::cout };
void sender()
{
asio::io_service executor;
auto big_buffer = std::vector<char>(1000000, 'a');
protocol::socket sock(executor);
rx_ready.wait();
asio::error_code ec;
if(sock.connect(protocol::endpoint(asio::ip::address_v4(0x7f000001), 12345)), ec) {
stdout_emit("connect failure: ", ec.message());
return;
}
auto written = asio::write(sock, asio::buffer(big_buffer), ec);
stdout_emit("wrote: ", written);
if (ec) {
stdout_emit("write failure: ", ec.message());
}
sock.shutdown(protocol::socket::shutdown_send, ec);
if (ec) {
stdout_emit("shutdown failure: ", ec.message());
}
sock.close(ec);
if (ec) {
stdout_emit("close failure: ", ec.message());
}
}
void start_receiving(protocol::socket& s)
{
auto huge_buffer_ptr = std::make_shared<std::vector<char>>(1000000);
s.async_read_some(asio::buffer(*huge_buffer_ptr), [huge_buffer_ptr, &s](asio::error_code ec, std::size_t size)
{
stdout_emit("read ", size, " bytes");
if (ec)
{
stdout_emit("read error: ", ec.message());
}
else
{
start_receiving(s);
}
});
}
void receiver()
{
asio::io_service executor;
protocol::acceptor acceptor(executor);
auto ep = protocol::endpoint(protocol::v4(), 12345);
acceptor.open(ep.protocol());
acceptor.bind(ep);
acceptor.listen();
protocol::socket s(executor);
acceptor.async_accept(s, [&](asio::error_code ec){
if (ec) {
stdout_emit("accept: ", ec.message());
}
else
{
start_receiving(s);
}
});
rx_ready.notify();
executor.run();
}
int main()
{
auto t = std::thread(receiver);
sender();
t.join();
}
sample results:
read 393216 bytes
wrote: 1000000
read 606784 bytes
read 0 bytes
read error: End of file
Process finished with exit code 0
changing the read and write buffers to 10,000,000 bytes gave me this:
read 393216 bytes
read 638820 bytes
read 639028 bytes
read 639028 bytes
read 639028 bytes
read 638820 bytes
read 639028 bytes
read 639028 bytes
read 639028 bytes
read 638820 bytes
read 639028 bytes
read 639028 bytes
read 639028 bytes
read 638820 bytes
wrote: 10000000
read 639028 bytes
read 639028 bytes
read 22196 bytes
read 0 bytes
read error: End of file
Process finished with exit code 0
I am newcomer in area of network and internet,therefore want to apologize for may be stupid question. I do not understand whether there are other ways to send data from client socket to server's axcept putting data into a stream using method QIODevice::write(QByteArray& ). If that is the only way how server should recognize what exactly data has been sent to it ? For example, we may have QString message as a usual input data, but also sometimes QString as the name of further receiver of future data. It is possible to describe all variants but the slot connected to readyRead() signal seems to be of enormous
size at this case.
Eventually, is there way to direct data to some exact server's functions ?
Qt Solutions has a library to make Qt servers easily:
Qt Solutions
And Json format it is a beautiful way to communicate
You need to define comman data type both side( client and server ). before you sent data packet you should write size of data packet to first four byte of data packet. at the server side check size of data receiving from client with first four bytes. and deserialize data which you how did you serialize at client side. I used this method a long time and there is any problem occured to today. i will give you sample code for you.
Client Side:
QBuffer buffer;
buffer.open(QIODevice::ReadWrite);
QDataStream in(&buffer);
in.setVersion(QDataStream::Qt_5_2);
in << int(0); // for packet size
in << int(3); // int may be this your data type or command
in << double(4); // double data
in << QString("asdsdffdggfh"); //
in << QVariant("");
in << .... // any data you can serialize which QDatastream accept
in.device()->seek(0); // seek packet fisrt byte
in << buffer.data().size(); // and write packet size
array = buffer.data();
this->socket->write(arr);
this->socket->waitForBytesWritten();
Server Side:
QDatastream in(socket);
//define this out of this scope and globally
int expectedByte = -1;
if( expectedByte < socket->bytesAvailable() && expectedByte == -1 )
{
in >> expectedByte;
}
if(expectedByte - socket->bytesAvailable()- (int)sizeof(int) != 0){
return;
}
// if code here, your packet received completely
int commandOrDataType;
in >> commandOrDataType;
double anyDoubleValue;
in >> anyDoubleValue;
QString anyStringValue;
in >> anyStringValue;
QVariant anyVariant;
in >> anyVariant;
// and whatever ...
// do something with above data
//you must set expectedByte = -1;
// if your proccessing doing any thing at this time there is no any data will be received while expectedByte != -1, but may be socket buffer will be filling. you should comfirm at the begining of this function
expectedByte = -1;
Hope this helpfully! :)
I'm writing a distributed system in c++ using TCP/IP and sockets.
For each of my messages, I need to receive the first 5 bytes to know the full length of the incoming message.
What's the best way to do this?
recv() only 5 bytes, then recv() again. if I choose this, would it be safe to assume I'll get 0 or 5 bytes in the recv (aka not write a loop to keep trying)?
use MSG_PEEK
recv() some larger buffer size, then read the first 5 bytes and allocate the final buffer then.
You don't need to know anything. TCP is a stream protocol, and at any given moment you can get as little as one byte, or as much as multiple megabytes of data. The correct and only way to use a TCP socket is to read in a loop.
char buf[4096]; // or whatever
std::deque<char> data;
for (int res ; ; )
{
res = recv(fd, buf, sizeof buf, MSG_DONTWAIT);
if (res == -1)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
break; // done reading
}
else
{
// error, break, die
}
}
if (res == 0)
{
// socket closed, finalise, break
}
else
{
data.insert(data.end(), buf, buf + res);
}
}
The only purpose of the loop is to transfer data from the socket buffer to your application. Your application must then decide independently if there's enough data in the queue to attempt extraction of some sort of higher-level application message.
For example, in your case you would check if the queue's size is at least 5, then inspect the first five bytes, and then check if the queue holds a complete application message. If no, you abort, and if yes, you extract the entire message and pop if off from the front of the queue.
Use a state machine with two states:
First State.
Receive bytes as they arrive into a buffer. When there are 5 or more bytes perform your check on those first 5 and possibly process the rest of the buffer. Switch to the second state.
Second State.
Receive and process bytes as they arrive to the end of the message.
to answer your question specifically:
it's not safe to assume you'll get 0 or 5. it is possible to get 1-4 as well. loop until you get 5 or an error as others have suggested.
i wouldn't bother with PEEK, most of the time you'll block (assuming blocking calls) or get 5 so skip the extra call into the stack.
this is fine too but adds complexity for little gain.
I'm writing a UDP client that sends a string to a server, when the server sends back several packets, the behavior of the program is not as my expectation. I want to process any incoming packet by process() one by one until the entry buffer gets empty, but I think there is a problem related to blocking behavior of recv.
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <winsock.h>
using namespace std;
void process(const char *in, int size)
{
fprintf(stdout, "%s\n", in);
}
int main()
{
char quack_addr[] = "127.0.0.1";
unsigned short quack_port = 9091;
WSAData data;
WSAStartup(MAKEWORD(2, 2), &data);
sockaddr_in qserver;
qserver.sin_family = AF_INET;
qserver.sin_addr.s_addr = inet_addr(quack_addr);
qserver.sin_port = htons(quack_port);
SOCKET client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (client <= 0)
{
fprintf(stderr, "Error - Can not create socket.\n");
exit(1);
}
while (true)
{
const int MAX = 1024;
char sbuf[MAX];
char rbuf[MAX];
fprintf(stdout, ": ");
fgets(sbuf, MAX, stdin);
int slen = strlen(sbuf);
int r = sendto(client,sbuf,slen,0,(sockaddr*)&qserver,sizeof(qserver));
// Current code:
// int rlen = recv(client, rbuf, MAX, 0);
// if (rlen > 0)
// {
// rbuf[rlen] = 0;
// process(rbuf, rlen);
// }
// Question starts here:
//
// While there is data in queue do:
// {
// (break if there is no data)
// int rlen = recv(client, rbuf, MAX, 0);
// rbuf[rlen] = 0;
// process(rbuf, rlen);
// }
}
return 0;
}
How can I check if the buffer is empty or not, before calling recv(...) ?
The problem occurs in this scenario:
User is typing a command in the client program (cmd1).
Simultaneously, the server sends 3 packets to client (pkt1, pkt2, pkt3).
After pressing Enter in the client side, I expect to receive those 3 packets and probably the result corresponding to cmd1, and process() all of them one by one.
But after pressing Enter in stage 3, I receive pkt1! and after sending another command to the server I will receive pkt2 and so on ...!
I know my code is not enough to handle this issue, so, my question is how to handle it?
Note: I'm using netcat -L -p 9091 -u as UDP server
I think the problems (unsatisfying behavior you do not describe) come from a different source. Let me just list some ideas and comments c./ what was said before:
(1) recvfrom() blocks too. However, you want to use it. Your communication currently sends and receives from loopback, which is fine for your toy program (but: see below). When receiving UDP data, with recv() you don't know who sent it, as the socket was never connect()ed. Use recvfrom() to prepare yourself for some minimal error checking in a more serious program
(2) as select() suspends the program to i/o availibity, it would only put any issue with your socket blocking to a different level. But this is not the problem
(3) to check is the receive buffer is empty, use flag MSG_PEEK in recvfrom() in an appropriate position. It's usually only used to deal with scarce memory, but it should do the job.
(4) reason 1 why I believe you see the issues you don't describe in more detail:
UDP datagrams preserve message boundaries. This means that recvfrom() will read in an entire chunk of data making up any message sent. However, if the buffer you read this into is smaller than the data read, any surplus will be silently discarded. So make sure you have a big buffer (65k something ideally).
(5) reason 2:
You receive any data sent to the loopback. If you're currently also connected to some net (sat, the Internet), what you catch might actually be from a different source than you expect. So at least in a resting phase, disconnect.
Blocking shouldn't be an issue. Your basic logic, when coded cleanly, is:
Recvfrom() (block/wait until ready)
Process
Peek if buffer empty
Exit if yes
Loop back to receive more if not,
and you seem to want to do this currently. As you don't multi-thread, optimize fie perfiormance, or similar, you shouldn't care about blocking. If you find your receive buffer too small, increase its size using
Setsockopt() for optName SO_RCVBUF
Use select() (with a suitable timeout) to check for incoming data prior to calling recv().
Something like the following (nonportable code)
#include <winsock2.h>
...
/* somewhere after your sendto, or your first recv */
fd_set recv_set;
timeval tv = {1, 0}; /* one second */
FD_ZERO(&recv_set);
FD_SET(client, &recv_set);
while (select(0, &recv_set, NULL, NULL, &tv) > 0)
{
/* recv... */
FD_SET(client, &recv_set); /* actually redundant, since it is already set */
}
iPhone sometimes bugs out and doesn't let me post comments. Thanks, Steve. This is just continuing the conversation.
I assume this means 'uncomment to 'question starts here'. Partial answer, as this still depends on my 2nd comment; this is more or less than what to expect. Assuming the three messages to be sent by the server are already queued up, after you hit enter for the first time, your packet is sent (never blocked as sendto() doesn't block for UDP), received by the server and (I assume, see above, echoed back and added to the FIFO receive buffer in which you alread have three messages queued up. You then have a recv() in your program which receives the first queued up message, printing it out. Your current logic goes back to top of loop, expect another input and waits for it (so this isn't blocked on a socket level, but as your program requests input, eg simply 'enter'), then comes to the second originally sent message (by the server) and processes that one. One more loop, and all three are done. Hitting enter again, and assuming the server echoes what you sent, you should start receiving your typed in messages (which might be empty if you only hit enter). The loop will currently not exit except you kill it.