Linux Netcat works as Expected but not QTCPSocket on Raspberry Pi - linux

I have 2 Raspberry Pis, one sender and one receiver which acts as an Access Point using a USB WiFi dongle. I have Qt 5.4.0 code on the sender that uses a USB/FTDI XBee SB6 WiFi unit to send TCP packets to the receiver Pi after connecting to it's Access Point successfully as a client.
The code is sending TCP packets correctly through the XBee to the receiver Pi because I can use the Netcat program on the receiver and watch the packets arrive successfully on port 0x2616 ( 9750 ):
>> sudo nc -l 10.10.10.1 9750
>> HELLOHELLOHELLO
When I try to replace Netcat on the receiver Pi with the following Qt code using QTCPSocket, it never receives any data on the socket. By this I mean that the 'readyRead()' slot is never called. I've run it as sudo and the sender Pi is doing exactly the same transfer as it was when Netcat was capturing the output. What is going on? Am I connecting wrong with QTCPSocket to the local port? How can I make it work? Thanks!
#include "tcpreceiver.h"
// Debug
#include <QDebug>
#define API_DEBUG true
#include <QApplication>
TcpReceiver::TcpReceiver(QObject *parent) :
QObject(parent)
{
// Debug
qDebug() << "Setting up a TCP Socket...";
// Create a socket
m_Socket = new QTcpSocket(this);
// Bind to the 2616 port
m_Socket->connectToHost("10.10.10.1", 0x2616);
//m_Socket->connectToHost( QHostAddress::Any, 0x2616 );
qDebug() << "Socket is valid: " << m_Socket->isValid();
//qDebug() << "Socket value: " << m_Socket->
// Get notified that data is incoming to the socket
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
// Init to Zero
m_NumberTCPPacketsReceived = 0;
}
void TcpReceiver::readyRead() {
qDebug() << "Received data...";
// When data comes in
QByteArray buffer;
buffer.resize(m_Socket->bytesAvailable());
// Cap buffer size
int lenToRead = buffer.size();
if ( buffer.size() > NOMINAL_AUDIO_BUFFER_SIZE ) {
lenToRead = NOMINAL_AUDIO_BUFFER_SIZE;
}
// Read the data from the TCP Port
m_Socket->read(buffer.data(), lenToRead);
...
// Count up
m_NumberTCPPacketsReceived++;
}

Here is how you do it:
#include "tcpreceiver.h"
// Debug
#include <QDebug>
#include <QHostAddress>
TcpReceiver::TcpReceiver(QObject *parent) :
QObject(parent)
{
// Create a server
qDebug() << "Creating a TCP Server...";
// Create the server
m_Server = new QTcpServer(this);
// Listen on the proper port
m_Server->listen( QHostAddress::Any, 0x2616 );
// Hook up signal and slots
connect(m_Server, SIGNAL(newConnection()), this, SLOT(gotNewConnection()));
connect(m_Server, SIGNAL(acceptError(QAbstractSocket::SocketError)), this, SLOT(error()));
}
void TcpReceiver::gotNewConnection() {
qDebug() << "Got a new TCP Connection";
// Get the socket
m_Socket = m_Server->nextPendingConnection();
if(m_Socket->state() == QTcpSocket::ConnectedState)
{
qDebug() << "Socket was connected at: " << m_Socket->peerAddress();
}
// Hook up some signals / slots
connect(m_Socket, SIGNAL(disconnected()),this, SLOT(disconnected()));
connect(m_Socket, SIGNAL(readyRead()),this, SLOT(readyRead()));
}
void TcpReceiver::disconnected() {
qDebug() << "Socket Disconnected...";
// Cleanup
m_Socket->deleteLater();
}
void TcpReceiver::error() {
qDebug() << "Error: " << m_Server->errorString();
}
void TcpReceiver::readyRead() {
qDebug() << "Received data...";
// Now read data
QByteArray buffer;
if (m_Socket->canReadLine()) {
buffer = m_Socket->readLine();
qDebug() << "Got Data: " << buffer;
}
}

Related

Virtual COM Port STM32 and Qt Serial Port

My aim is to enable communication via USB CDC HS on STM32 with Ubuntu 20.04 based PC in Qt app created in QtCreator.
So far I've managed to run communication via UART and everything is working fine. Then I decided to switch to USB and I still can read incoming data (but only in CuteCom) and in my Qt app nothing appears.
To be honest I have no idea what is going on and where to look for mistakes. Here I put the code:
void MainWindow::on_pushButtonConnect_clicked()
{
if (ui->comboBoxDevices->count() == 0){
this->addToLogs("No devices found.");
return;
}
QString portName = ui->comboBoxDevices->currentText().split(" ").first();
this->device->setPortName(portName);
this->device->setBaudRate(QSerialPort::Baud115200);
this->device->setDataBits(QSerialPort::Data8);
this->device->setParity(QSerialPort::NoParity);
this->device->setStopBits(QSerialPort::OneStop);
this->device->setFlowControl(QSerialPort::NoFlowControl);
if(device->open(QIODevice::ReadWrite)){
this->addToLogs("Port opened. Setting the connection params...");
this->addToLogs("UART enabled.");
qDebug() << "Writing down the parameters...";
qDebug() << "Baud rate:" << this->device->baudRate();
qDebug() << "Data bits:" << this->device->dataBits();
qDebug() << "Stop bits:" << this->device->stopBits();
qDebug() << "Parity:" << this->device->parity();
qDebug() << "Flow control:" << this->device->flowControl();
qDebug() << "Read buffer size:" << this->device->readBufferSize();
qDebug() << "Read buffer size:" << this->device->portName();
connect(this->device, SIGNAL(readyRead()), this, SLOT(readFromPort()));
} else {
this->addToLogs("The port can not be opened.");
}
And the readFromPort() function:
void MainWindow::readFromPort()
{
while(this->device->canReadLine()){
QString line = this->device->readLine();
qDebug() << line;
QString terminator = "\r";
int pos = line.lastIndexOf(terminator);
qDebug()<<line.left(pos);
this->addToLogs(line.left(pos));
}
}
Do you have any idea what might be wrong or not set properly? Would be thankful for all help.
As it seems, in my code I put commands to read the port in if (with function canReadLine()). When I commented the whole condition out leaving just the reading, everything worked fine.

Cannot create children for a parent that is in a different thread qt c++

I am trying to run a separate thread from the main thread where mqttclient is initialised and moved to a new thread.
Previously there were problems of signal slot. Which i resumed by creating a separate class (mqtthandler) running from main thread and connected to mqttclient class via signal slots which are delivered to qml.
I tested the codes by running them in same thread. They all work.
Now when I tried to move mqttclient in another thread it causes problem. I know the reason why it is giving me the problem but I dont know, the solution to it.
The problem creator is mqttclient constructor because it connecttohost in constructor only.
I need to connecttohost mqttclient but somehow in new thread.
I also tried to make connecttohost in subscribe function (of mqttclient itself) which at later stage is called via mqtthandler which is called by qml. Still it doesnt work.
main.cpp
QGuiApplication app(argc, argv);
QThread mqttclientThread;
// When the application is quitting, so should the worker thread
QObject::connect(&app, &QCoreApplication::aboutToQuit, &mqttclientThread, &QThread::quit);
MqttClient * mqttclientObj = new MqttClient;
mqttclientObj->moveToThread(&mqttclientThread);
mqttclientThread.start();
qDebug() << "Main client status " << mqttclientObj->state();
MqttHandler * mqttHandlerObj = new MqttHandler;
QObject::connect(mqttHandlerObj, &MqttHandler::mqtthandler_getaddr_signal, mqttclientObj, &MqttClient::getAddr);
QObject::connect(mqttclientObj, &MqttClient::sensorValueChanged, mqttHandlerObj,&MqttHandler::mqtthandler_sensorValueChanged_slot);
qDebug() << "Main " << QThread::currentThread();
mqttclient.cpp
MqttClient::MqttClient(QObject *parent)
: QMqttClient(parent)
{
this->setHostname("127.0.0.1");
this->setPort(1883);
this->connectToHost();
m_listTopic.clear();
vSimulateSensorValues();
connect(this, SIGNAL(publishsignals(QString, QString)),this, SLOT(publishmsg(QString,QString)));
}
MqttSubscription* MqttClient::subscribe(const QString &topic)
{
auto sub = QMqttClient::subscribe(topic, 0);
MqttSubscription* result = new MqttSubscription(sub, this);
qDebug() << "subscribe " << QThread::currentThread();
m_listTopic.append(topic);
return result;
}
MqttSubscription::MqttSubscription(QMqttSubscription *s, MqttClient *c)
: sub(s),
client(c)
{
connect(sub, &QMqttSubscription::messageReceived, client, &MqttClient::handleMessage);
qDebug() << "mqttsubconn " << QThread::currentThread();
}
MqttSubscription::~MqttSubscription()
{
}
The Error
Main client status 1
Main QThread(0x7fcfa7400530)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QMqttConnection(0x7fcfa75a3008), parent's thread is QThread(0x7fcfa7400530), current thread is QThread(0x7ffee1cb4a30)
QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
/*****************************************************************************************************************************************************************************************************************************/
Update
updated mqttclient class
MqttClient::MqttClient(QObject *parent)
: QMqttClient(parent)
{
}
void MqttClient::Init()
{
this->setHostname("127.0.0.1");
this->setPort(1883);
this->connectToHost();
QThread::sleep(10);
m_listTopic.clear();
vSimulateSensorValues();
connect(this, &MqttClient::publishsignals, this, &MqttClient::publishmsg);
}
MqttSubscription* MqttClient::subscribe(const QString &topic)
{
// this->setParent(this);
auto sub = QMqttClient::subscribe(topic, 0);
qDebug() << "state " << this->state();
MqttSubscription* result = new MqttSubscription(sub, this);
qDebug() << "subscribe " << QThread::currentThread();
m_listTopic.append(topic);
return result;
}
void MqttClient::handleMessage(const QMqttMessage &qmsg)
{
emit MqttClient::sensorValueChanged(qmsg.payload(),qmsg.topic().name());
qDebug() << "Handle " << QThread::currentThread();
}
void MqttClient::getAddr(QString value)
{
qDebug() << "c++ " + value;
subscribe(value);
qDebug() << "getaddr " << QThread::currentThread();
}
MqttSubscription::MqttSubscription(QMqttSubscription *s, MqttClient *c)
: sub(s),
client(c)
{
qDebug() << "Here " << client->state();
qDebug() << client;
connect(sub, &QMqttSubscription::messageReceived, client, &MqttClient::handleMessage);
qDebug() << "mqttsubconn " << QThread::currentThread();
}
MqttSubscription::~MqttSubscription()
{
}
and main.cpp
QGuiApplication app(argc, argv);
QThread mqttclientThread;
// When the application is quitting, so should the worker thread
QObject::connect(&app, &QCoreApplication::aboutToQuit, &mqttclientThread, &QThread::quit);
MqttClient * mqttclientObj = new MqttClient;
mqttclientObj->moveToThread(&mqttclientThread);
QObject::connect(&mqttclientThread, &QThread::started, mqttclientObj, &MqttClient::Init);
mqttclientThread.start();
MqttHandler * mqttHandlerObj = new MqttHandler;
QObject::connect(mqttHandlerObj, &MqttHandler::mqtthandler_getaddr_signal, mqttclientObj, &MqttClient::getAddr);
QObject::connect(mqttclientObj, &MqttClient::sensorValueChanged, mqttHandlerObj,&MqttHandler::mqtthandler_sensorValueChanged_slot);
qDebug() << "Main " << QThread::currentThread();
The update gave rise to another problem
Main QThread(0x7f925750e790)
state 1
Here 1
MqttClient(0x7f9257600f90)
QObject::connect(QMqttSubscription, MqttClient): invalid null parameter
QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
If the problem is, as you suggest, the call to connectToHost in the MqttClient constructor then why not simply move the offending code into a slot?
MqttClient::MqttClient(QObject *parent)
: QMqttClient(parent)
{
}
void MqttClient::init ()
{
this->setHostname("127.0.0.1");
this->setPort(1883);
this->connectToHost();
m_listTopic.clear();
vSimulateSensorValues();
connect(this, &MqttClient::publishsignals, this, &MqttClient::publishmsg);
}
Then in main connect that slot to the QThread::started signal...
.
.
.
MqttClient *mqttclientObj = new MqttClient;
mqttclientObj->moveToThread(&mqttclientThread);
/*
* Connect MqttClient::init slot to QThread::started signal.
*/
connect(&mqttclientThread, &QThread::started, mqttclientObj, &MqttClient::init);
mqttclientThread.start();
.
.
.

Asio on Linux stalls in epoll()

We're experiencing a problem with asynchronous operation of standalone (non-Boost) Asio 1.10.6 on Linux, which is demonstrated using the following test app:
#define ASIO_STANDALONE
#define ASIO_HEADER_ONLY
#define ASIO_NO_EXCEPTIONS
#define ASIO_NO_TYPEID
#include "asio.hpp"
#include <chrono>
#include <iostream>
#include <list>
#include <map>
#include <thread>
static bool s_freeInboundSocket = false;
static bool s_freeOutboundSocket = false;
class Tester
{
public:
Tester(asio::io_service& i_ioService, unsigned i_n)
: m_inboundStrand(i_ioService)
, m_listener(i_ioService)
, m_outboundStrand(i_ioService)
, m_resolver(i_ioService)
, m_n(i_n)
, m_traceStart(std::chrono::high_resolution_clock::now())
{}
~Tester()
{}
void TraceIn(unsigned i_line)
{
m_inboundTrace.emplace_back(i_line, std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - m_traceStart));
}
void AbortIn(unsigned i_line)
{
TraceIn(i_line);
abort();
}
void TraceOut(unsigned i_line)
{
m_outboundTrace.emplace_back(i_line, std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - m_traceStart));
}
void AbortOut(unsigned i_line)
{
TraceOut(i_line);
abort();
}
void DumpTrace(std::map<unsigned, unsigned>& o_counts)
{
std::cout << "## " << m_n << " ##\n";
std::cout << "-- " << m_traceStart.time_since_epoch().count() << "\n";
std::cout << "- in - - out -\n";
auto in = m_inboundTrace.begin();
auto out = m_outboundTrace.begin();
while ((in != m_inboundTrace.end()) || (out != m_outboundTrace.end()))
{
if (in == m_inboundTrace.end())
{
++o_counts[out->first];
std::cout << " " << out->first << " : " << out->second.count() << "\n";
++out;
}
else if (out == m_outboundTrace.end())
{
++o_counts[in->first];
std::cout << in->first << " : " << in->second.count() << "\n";
++in;
}
else if (out->second < in->second)
{
++o_counts[out->first];
std::cout << " " << out->first << " : " << out->second.count() << "\n";
++out;
}
else
{
++o_counts[in->first];
std::cout << in->first << " : " << in->second.count() << "\n";
++in;
}
}
std::cout << std::endl;
}
//////////////
// Inbound
void Listen(uint16_t i_portBase)
{
m_inboundSocket.reset(new asio::ip::tcp::socket(m_inboundStrand.get_io_service()));
asio::error_code ec;
if (m_listener.open(asio::ip::tcp::v4(), ec)
|| m_listener.bind(asio::ip::tcp::endpoint(asio::ip::tcp::v4(), i_portBase+m_n), ec)
|| m_listener.listen(-1, ec))
{
AbortIn(__LINE__); return;
}
TraceIn(__LINE__);
m_listener.async_accept(*m_inboundSocket,
m_inboundStrand.wrap([this](const asio::error_code& i_error)
{
OnInboundAccepted(i_error);
}));
}
void OnInboundAccepted(const asio::error_code& i_error)
{
TraceIn(__LINE__);
if (i_error) { AbortIn(__LINE__); return; }
asio::async_read_until(*m_inboundSocket, m_inboundRxBuf, '\n',
m_inboundStrand.wrap([this](const asio::error_code& i_err, size_t i_nRd)
{
OnInboundReadCompleted(i_err, i_nRd);
}));
}
void OnInboundReadCompleted(const asio::error_code& i_error, size_t i_nRead)
{
TraceIn(__LINE__);
if (i_error.value() != 0) { AbortIn(__LINE__); return; }
if (bool(i_error)) { AbortIn(__LINE__); return; }
if (i_nRead != 4) { AbortIn(__LINE__); return; } // "msg\n"
std::istream is(&m_inboundRxBuf);
std::string s;
if (!std::getline(is, s)) { AbortIn(__LINE__); return; }
if (s != "msg") { AbortIn(__LINE__); return; }
if (m_inboundRxBuf.in_avail() != 0) { AbortIn(__LINE__); return; }
asio::async_read_until(*m_inboundSocket, m_inboundRxBuf, '\n',
m_inboundStrand.wrap([this](const asio::error_code& i_err, size_t i_nRd)
{
OnInboundWaitCompleted(i_err, i_nRd);
}));
}
void OnInboundWaitCompleted(const asio::error_code& i_error, size_t i_nRead)
{
TraceIn(__LINE__);
if (i_error != asio::error::eof) { AbortIn(__LINE__); return; }
if (i_nRead != 0) { AbortIn(__LINE__); return; }
if (s_freeInboundSocket)
{
m_inboundSocket.reset();
}
}
//////////////
// Outbound
void Connect(std::string i_host, uint16_t i_portBase)
{
asio::error_code ec;
auto endpoint = m_resolver.resolve(asio::ip::tcp::resolver::query(i_host, std::to_string(i_portBase+m_n)), ec);
if (ec) { AbortOut(__LINE__); return; }
m_outboundSocket.reset(new asio::ip::tcp::socket(m_outboundStrand.get_io_service()));
TraceOut(__LINE__);
asio::async_connect(*m_outboundSocket, endpoint,
m_outboundStrand.wrap([this](const std::error_code& i_error, const asio::ip::tcp::resolver::iterator& i_ep)
{
OnOutboundConnected(i_error, i_ep);
}));
}
void OnOutboundConnected(const asio::error_code& i_error, const asio::ip::tcp::resolver::iterator& i_endpoint)
{
TraceOut(__LINE__);
if (i_error) { AbortOut(__LINE__); return; }
std::ostream(&m_outboundTxBuf) << "msg" << '\n';
asio::async_write(*m_outboundSocket, m_outboundTxBuf.data(),
m_outboundStrand.wrap([this](const asio::error_code& i_error, size_t i_nWritten)
{
OnOutboundWriteCompleted(i_error, i_nWritten);
}));
}
void OnOutboundWriteCompleted(const asio::error_code& i_error, size_t i_nWritten)
{
TraceOut(__LINE__);
if (i_error) { AbortOut(__LINE__); return; }
if (i_nWritten != 4) { AbortOut(__LINE__); return; } // "msg\n"
TraceOut(__LINE__);
m_outboundSocket->shutdown(asio::socket_base::shutdown_both);
asio::async_read_until(*m_outboundSocket, m_outboundRxBuf, '\n',
m_outboundStrand.wrap([this](const asio::error_code& i_error, size_t i_nRead)
{
OnOutboundWaitCompleted(i_error, i_nRead);
}));
}
void OnOutboundWaitCompleted(const asio::error_code& i_error, size_t i_nRead)
{
TraceOut(__LINE__);
if (i_error != asio::error::eof) { AbortOut(__LINE__); return; }
if (i_nRead != 0) { AbortOut(__LINE__); return; }
if (s_freeOutboundSocket)
{
m_outboundSocket.reset();
}
}
private:
//////////////
// Inbound
asio::io_service::strand m_inboundStrand;
asio::ip::tcp::acceptor m_listener;
std::unique_ptr<asio::ip::tcp::socket> m_inboundSocket;
asio::streambuf m_inboundRxBuf;
asio::streambuf m_inboundTxBuf;
//////////////
// Outbound
asio::io_service::strand m_outboundStrand;
asio::ip::tcp::resolver m_resolver;
std::unique_ptr<asio::ip::tcp::socket> m_outboundSocket;
asio::streambuf m_outboundRxBuf;
asio::streambuf m_outboundTxBuf;
//////////////
// Common
unsigned m_n;
const std::chrono::high_resolution_clock::time_point m_traceStart;
std::vector<std::pair<unsigned, std::chrono::nanoseconds>> m_inboundTrace;
std::vector<std::pair<unsigned, std::chrono::nanoseconds>> m_outboundTrace;
};
static int Usage(int i_ret)
{
std::cout << "[" << i_ret << "]" << "Usage: example <nThreads> <nConnections> <inboundFree> <outboundFree>" << std::endl;
return i_ret;
}
int main(int argc, char* argv[])
{
if (argc < 5)
return Usage(__LINE__);
const unsigned nThreads = unsigned(std::stoul(argv[1]));
if (nThreads == 0)
return Usage(__LINE__);
const unsigned nConnections = unsigned(std::stoul(argv[2]));
if (nConnections == 0)
return Usage(__LINE__);
s_freeInboundSocket = (*argv[3] == 'y');
s_freeOutboundSocket = (*argv[4] == 'y');
const uint16_t listenPortBase = 25000;
const uint16_t connectPortBase = 25000;
const std::string connectHost = "127.0.0.1";
asio::io_service ioService;
std::cout << "Creating." << std::endl;
std::list<Tester> testers;
for (unsigned i = 0; i < nConnections; ++i)
{
testers.emplace_back(ioService, i);
testers.back().Listen(listenPortBase);
testers.back().Connect(connectHost, connectPortBase);
}
std::cout << "Starting." << std::endl;
std::vector<std::thread> threads;
for (unsigned i = 0; i < nThreads; ++i)
{
threads.emplace_back([&]()
{
ioService.run();
});
}
std::cout << "Waiting." << std::endl;
for (auto& thread : threads)
{
thread.join();
}
std::cout << "Stopped." << std::endl;
return 0;
}
void DumpAllTraces(std::list<Tester>& i_testers)
{
std::map<unsigned, unsigned> counts;
for (auto& tester : i_testers)
{
tester.DumpTrace(counts);
}
std::cout << "##############################\n";
for (const auto& count : counts)
{
std::cout << count.first << " : " << count.second << "\n";
}
std::cout << std::endl;
}
#if defined(ASIO_NO_EXCEPTIONS)
namespace asio
{
namespace detail
{
template <typename Exception>
void throw_exception(const Exception& e)
{
abort();
}
} // namespace detail
} // namespace asio
#endif
We compile as follows (the problem only occurs in optimised builds):
g++ -o example -m64 -g -O3 --no-exceptions --no-rtti --std=c++11 -I asio-1.10.6/include -lpthread example.cpp
We're running on Debian Jessie. uname -a reports (Linux <hostname> 3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u2 (2016-10-19) x86_64 GNU/Linux.
The problem appears under both GCC (g++ (Debian 4.9.2-10) 4.9.2) and Clang (Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)).
[EDITED TO ADD: It also happens on Debian Stretch Linux <hostname> 4.6.0-1-amd64 #1 SMP Debian 4.6.1-1 (2016-06-06) x86_64 GNU/Linux with g++ (Debian 6.2.1-5) 6.2.1 20161124.]
In summary, the test app does the following:
We create N connections, each consisting of an inbound (listening)
end and an outbound (connecting) end. Each inbound listener is bound
to a unique port (starting at 25000), and each outbound connector
uses a system-selected originating port.
The inbound end performs an async_accept, and on
completion issues an async_read. When the read completes it issues
another async_read that we expect to return eof. When that
completes, we either free the socket immediately, or leave it as-is
(with no pending async operations) to be cleaned up by the relevant
destructors at program exit. (Note that the listener socket is
always left as-is, with no pending accept, until exit.)
The outbound end performs an async_connect, and on completion issues
an async_write. When the write completes it issues a shutdown
(specifically, shutdown(both)) followed by an async_read that we
expect to return eof. On completion, we once again either leave the
socket as-is, with no pending operations, or we free it immediately.
Any error or unexpected receive data results in an immediate abort()
call.
The test app lets us specify the number of worker threads for the
io_service, as well as the total number of connections to create, as
well as flags controlling whether inbound and outbound sockets
respectively are freed or left as-is.
We run the test app repeatedly, specifying 50 threads and 1000
connections.
i.e. while ./example 50 1000 n y >out.txt ; do echo -n . ; done
If we specify that all sockets are left as-is, the test loop runs indefinitely. To avoid muddying the waters with SO_REUSEADDR considerations, we take care that no sockets are in TIME_WAIT state from a previous test run before we start the test, otherwise the listens can fail. But with this caveat satisfied, the test app runs literally hundreds, even thousands of times with no error. Similarly, if we specify that inbound sockets (but NOT outbound sockets) should be explicitly freed, all runs fine.
However, if we specify that outbound sockets should be freed, the app stalls after a variable number of executions - sometimes ten or fewer, sometimes a hundred or more, usually somewhere in between.
Connecting to the stalled process with GDB, we see that the main thread is waiting to join the worker threads, all but one of the worker threads are idle (waiting on an Asio internal condition variable), and that one worker thread is waiting in Asio's call to epoll(). The internal trace instrumentation verifies that some of the sockets are waiting on async operations to complete - sometimes the initial (inbound) accept, sometimes the (inbound) data read, and sometimes the final inbound or outbound reads that normally complete with eof.
In all cases, the other end of the connection has successfully done its bit: if the inbound accept is still pending, we see that the corresponding outbound connect has successfully completed, along with the outbound write; likewise if the inbound data read is pending, the corresponding outbound connect and write have completed; if the inbound EOF read is pending, the outbound shutdown has been performed, and likewise if the outbound EOF read is pending, the inbound EOF read has completed due to the outbound shutdown.
Examining the process's /proc/N/fdinfo shows that the epoll file descriptor is indeed waiting on the file descriptors indicated by the instrumentation.
Most puzzlingly, netstat shows nonzero RecvQ sizes for the waiting sockets - that is, sockets for which there is a read operation pending are shown to have receive data or close events ready to read. This is consistent with our instrumentation, in that it shows that write data has been delivered to the inbound socket, but has not yet been read (or alternatively that the outbound shutdown has issued a FIN to the inbound side, but that the EOF has not yet been 'read').
This leads me to suspect that Asio's epoll bookkeeping - in particular its edge-triggered event management - is getting out of sync somewhere due to a race condition. Clearly this is more than likely due to incorrect operations on my part, but I can't see where the problem would be.
All insights, suggestions, known issues, and pointing-out-glaring-screwups would be greatly appreciated.
[EDITED TO ADD: Using strace to capture kernel calls interferes with execution such that the stall doesn't happen. Using sysdig doesn't have this effect, but it currently doesn't capture the parameters of the epoll_wait and epoll_ctl syscalls. Sigh.]
This appears to have been resolved by the maintainer of ASIO:
See https://github.com/chriskohlhoff/asio/issues/180
and https://github.com/chriskohlhoff/asio/commit/669e6b8b9de1309927b29d8b6be3630cc69c07ac

XBee Linux Serial Port on Raspberry Pi

I have 2 Adafruit XBee 2 Modules each connected with 1 FTDI cable (ttyUSB0 and ttyUSB1)to the Raspberry Pi via a USB hub. I configure both XBee modules independently to be on the same PAN and then I try to read in a while loop with one, and write a simple message in a while loop in the other. For some reason I never read anything from the second port.
Here is the test code I am using.
Configure:
xbee::xbee(char* usbPort) {
/*
-> AT (check if xbee modem is responding)
<- OK
-> ATID (get current PAN)
<- 3332 (default, or something else)
-> ATID 3137 (set new id)
<- OK
-> ATID (check again)
<- 3137
-> ATWR (write the change to flash)
<- OK
*/
// Sleep for a little bit
QWaitCondition waitCondition;
QMutex mutex;
// Get a util object
Linuxutils util;
// Open a serial port
qDebug() << "Opening Serial Port:" << QString(usbPort);
char port[] = "ttyUSB1";
int fd = util.openSerialPort(port);
qDebug() << "Done opening Serial Port " << QString(usbPort) << ": " << fd;
int didConfigurePort = util.configureSerialPort(fd,9600);
qDebug() << "Did configure port successfully? " << didConfigurePort;
// Receive buffer
char rxBuffer[24];
/////////////////////////////////////////////////////////////////////////////
// Config Mode
memset(rxBuffer, 0, sizeof(rxBuffer));
char *msg = "+++";
qDebug() << "Writing config string to XBee ( +++ )";
util.writeToSerialPort(fd,msg);
qDebug() << "XBee written to, waiting for response of 'OK'";
while (true) {
int readNumberOfBytes = util.readFromSerialPort(fd,rxBuffer,4096);
printf("Received ( %d bytes ): %s\n", readNumberOfBytes,rxBuffer);
break;
}
/////////////////////////////////////////////////////////////////////////////
// AT (check if xbee modem is responding)
memset(rxBuffer, 0, sizeof(rxBuffer));
char *msg2 = "AT\n";
qDebug() << "Check if XBee is responding ( AT )";
util.writeToSerialPort(fd,msg2);
qDebug() << "XBee written to, waiting for response of 'OK'";
while (true) {
int readNumberOfBytes = util.readFromSerialPort(fd,rxBuffer,4096);
printf("Received ( %d bytes ): %s\n", readNumberOfBytes,rxBuffer);
break;
}
/////////////////////////////////////////////////////////////////////////////
// AT (get current PAN ID)
memset(rxBuffer, 0, sizeof(rxBuffer));
char *msg3 = "ATID\n";
qDebug() << "Get XBee PAN ID ( ATID )";
util.writeToSerialPort(fd,msg3);
qDebug() << "XBee written to, waiting for response which is integer of current PAN";
while (true) {
int readNumberOfBytes = util.readFromSerialPort(fd,rxBuffer,4096);
printf("Received ( %d bytes ): %s\n", readNumberOfBytes,rxBuffer);
break;
}
/////////////////////////////////////////////////////////////////////////////
// AT (get current PAN ID <VALUE>)
memset(rxBuffer, 0, sizeof(rxBuffer));
char *msg4 = "ATID 3137\n";
qDebug() << "Check if XBee is responding ( ATID 3137 )";
util.writeToSerialPort(fd,msg4);
qDebug() << "XBee written to, waiting for response after telling it to change to PAN 3137";
while (true) {
int readNumberOfBytes = util.readFromSerialPort(fd,rxBuffer,4096);
printf("Received ( %d bytes ): %s\n", readNumberOfBytes,rxBuffer);
break;
}
/////////////////////////////////////////////////////////////////////////////
// AT (get current PAN ID)
memset(rxBuffer, 0, sizeof(rxBuffer));
char *msg5 = "ATID\n";
qDebug() << "Get XBee PAN ID ( ATID )";
util.writeToSerialPort(fd,msg5);
qDebug() << "XBee written to, waiting for response which is integer of current PAN";
while (true) {
int readNumberOfBytes = util.readFromSerialPort(fd,rxBuffer,4096);
printf("Received ( %d bytes ): %s\n", readNumberOfBytes,rxBuffer);
break;
}
/////////////////////////////////////////////////////////////////////////////
// AT (get current PAN ID <VALUE>)
memset(rxBuffer, 0, sizeof(rxBuffer));
char *msg6 = "ATWR\n";
qDebug() << "Write new settings to XBee Flash ( ATWR )";
util.writeToSerialPort(fd,msg6);
qDebug() << "XBee written to, waiting for it to write to flash...";
while (true) {
int readNumberOfBytes = util.readFromSerialPort(fd,rxBuffer,4096);
printf("Received ( %d bytes ): %s\n", readNumberOfBytes,rxBuffer);
break;
}
// Close the file descriptor
close(fd);
}
Read:
void xbee::xbeeRead(char* usbPort) {
// Sleep
QWaitCondition waitCondition;
QMutex mutex;
waitCondition.wait(&mutex, 5000);
// Utils
Linuxutils util;
// File descriptor
int fd = util.openSerialPort(usbPort);
// Continually Read
char buffer[4096];
while (true) {
// Sleep
waitCondition.wait(&mutex, 1000);
qDebug() << "Waiting for data...";
int readNumberOfBytes = util.readFromSerialPort(fd,buffer,4096);
// Print results
printf("Read ( %d bytes ): %s\n", readNumberOfBytes,buffer);
}
// Close
close(fd);
}
Write:
void xbee::xbeeWrite(char *usbPort) {
// Sleep
QWaitCondition waitCondition;
QMutex mutex;
waitCondition.wait(&mutex, 5000);
// Utils
Linuxutils util;
// File descriptor
int fd = util.openSerialPort(usbPort);
// Continually Write
char *buffer = "Hello World!\n";
while (true) {
// Sleep
waitCondition.wait(&mutex, 1000);
int readNumberOfBytes = util.writeToSerialPort(fd,buffer);
// Print results
printf("Wrote ( %d bytes ): %s\n", readNumberOfBytes,buffer);
}
}
I can definitely configure each module - here is the example output for configuring ttyUSB0:
Input test type: 4
Opening Serial Port: "/dev/ttyUSB0"
Done opening Serial Port "/dev/ttyUSB0" : 6
Did configure port successfully? 0
Writing config string to XBee ( +++ )
XBee written to, waiting for response of 'OK'
Received ( 3 bytes ): OK
Check if XBee is responding ( AT )
XBee written to, waiting for response of 'OK'
Received ( 3 bytes ): OK
Get XBee PAN ID ( ATID )
XBee written to, waiting for response which is integer of current PAN
Received ( 5 bytes ): 3137
Check if XBee is responding ( ATID 3137 )
XBee written to, waiting for response after telling it to change to PAN 3137
Received ( 3 bytes ): OK
Get XBee PAN ID ( ATID )
XBee written to, waiting for response which is integer of current PAN
Received ( 5 bytes ): 3137
Write new settings to XBee Flash ( ATWR )
XBee written to, waiting for it to write to flash...
Received ( 3 bytes ): OK
Waiting for data...
Even though I can see that I am writing to the ttyUSB1 device in one while loop, I am not receiving anything at ttyUSB0.
Any ideas as to why this is happening?? Thanks!
Looks like you still have both XBees in command mode which will prevent any RF data transfer between these radio modules. Any serial data sent to the XBee will be ignored unless the line begins with the "AT" command prefix.
After you are done configuring each XBee, issue the "ATCN" command to exit command mode (there should be no "OK" response).
Then any serial data you send to the XBee will be transmitted by its radio, and the RF data received by the (other) XBee will be output on its serial port for reading by your program.
To re-enter command mode on an XBee module, nothing should be sent to the XBee serial port for one second (which is the default guard time), send a three character string of "+++" (three plus signs within 1 second), and then silence for another one second. The XBee should respond with an "OK" prompt.
All of this is standard Hayes modem AT command behavior.

QTcp[server and socket]: can't read file sent

Good morning, I’m looking for an example about sending a file from one pc to an other with QTcpSocket. I tried to create my own code. I have an application, in which, the user will choose a file from his DD ( all types) and send it to the TcpServer, this server will then send this file to the other clients.But, I have a problem, when i choose the file and i send it, in the client’s side, i have this message: file is sending , but in the server’s side, it shows me that the file isn’t recieved with it’s totaly bytes.
Any suggestion please. This is the function for sending the file in the client’s side:
void FenClient::on_boutonEnvoyer_2_clicked()
{
QString nomFichier = lineEdit->text();
QFile file(lineEdit->text());
if(!file.open(QIODevice::ReadOnly))
{
qDebug() << "Error, file can't be opened successfully !";
return;
}
QByteArray bytes = file.readAll();
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out << quint32(0);
out << nomFichier;
out << bytes;
out.device()->seek(0);
out << quint32((block.size() - sizeof(quint32)));
qDebug() << "Etat : envoi en cours...";
listeMessages->append("status : sending the file...");
socket->write(block);
}
and the server side:
void FenServeur::datarecieved()
{
QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
if(socket == 0)
{
qDebug() << "no Socket!";
return;
}
forever
{
QDataStream in(socket);
if(blockSize == 0)
{
if(socket->bytesAvailable() )
{
qDebug() << "Error < sizeof(quint32))";
return;
}
in >> blockSize;
}
if(socket->bytesAvailable() < blockSize)
{
qDebug() << "data not recieved with its total bytes";
return;
}
qDebug() << "!!!!!!";
QByteArray dataOut;
QString nameFile;
in >> nameFile >> dataOut;
QFile fileOut(nameFile);
fileOut.open(QIODevice::WriteOnly);
fileOut.write(dataOut);
fileOut.close();
blockSize = 0;
}
}
void FenServeur::sendToAll(const QString &message)
{
QByteArray paquet;
QDataStream out(&paquet, QIODevice::WriteOnly);
out << (quint32) 0;
out << message;
out.device()->seek(0);
out << (quint32) (paquet.size() - sizeof(quint32));
for (int i = 0; i < clients.size(); i++)
{
clients[i]->write(paquet);
}
}
So i can't write the file that the server recieved into a new file.
Any suggestion please!! and thanks in advance
Your code is waiting for the other side, but the other side is waiting for you. Any protocol that allows both sides to wait for each other is fundamentally broken.
TCP allows the sender to wait for the receiver but does not allow the receiver to wait for the sender. This makes sense because not allowing the sender to wait for the receiver requires an unlimited amount of buffering. Thus for any application layered on top of TCP, the receiver may not wait for the sender.
But you do:
if(socket->bytesAvailable() < blockSize)
{
qDebug() << "data not recieved with its total bytes";
return;
}
Here, you are waiting for the sender to make progress (bytesAvailable to increase) before you are willing to receive (pull data from the socket). But the sender is waiting for you to make progress before it is willing to send more data. This causes a deadlock. Don't do this.
Receive as much data as you can, as soon as you can, whenever you can. Never insist on receiving more data over the network before you will pull already received data from the network stack.

Resources