Segmentation fault on QThread termination. (deletion of 2 sockets running in it)
-
Hi,
I'm new to QT and trying to develop a multi threaded proxy.
I manage to create the input connection, move it into a thread, create the output connection inside it also, make them communicate but unfortunately I'm having a segmentation fault when I close the session... It was too beautiful...
I've been trying to understand what the problem could be all day and yesterday night but I really don't know...
Please help...
Here is the architecture of the Proxy:
The classes:- Connection (QObject holding a QTcpSocket that could be a QSslSocket)
- InputConnection and OutputConnection both inherit from Connection
- SessionHandler (object created when a client connect to the Proxy, it will be moved in a QThread and create both InputConnection and OutputConnection, make them in relation...)
- SessionManager: just to keep a list of the actives sessions
- Proxy: extends QTcpServer, overrides incomingConnection to create a SessionHandler and move it in a QThread at each client connection.
- MyThread, just override QThread to be able to log construction and deletion.
So, here is the code for incomingConnection:
void Proxy::incomingConnection(qintptr aSocketDescriptor){ QString str("New incoming connection: "); str += QString::number(aSocketDescriptor); log(str); MyThread * thread = new MyThread(aSocketDescriptor); thread->start(); // start the event loop // Create the InputController handler SessionHandler *input = iSessionMgr->newSession(aSocketDescriptor, thread); input->moveToThread(thread); connect(input, &SessionHandler::destroyed, thread, &QThread::quit); connect(thread, &QThread::finished, thread, &QObject::deleteLater); connect(thread, &QThread::destroyed, this, &Proxy::threadDeleted); emit input->startConnection(); // starting the connection inside the new thread }
Here is how the connections get started (in the thread)
bool Connection::startTcpConnection(const char* aHost, ushort aPort){ log("Starting connection..."); iSocket = new QTcpSocket(); // if server side socket we attach it to the socketDescriptor if (isServerSocket){ // Attach the socket to the native descriptor if(!iSocket->setSocketDescriptor(iSocketDescriptor)) { QString err("Setting socket Descriptor: "); err += iSocket->errorString(); log(err); emit socketError(err); return false; } } else { iSocket->connectToHost(aHost, aPort); // we need to wait... if(!iSocket->waitForConnected(5000)){ QString err("connecting to host: "); err += aHost; err += ":"; err += QString::number(aPort); err += ". socket error: "; err += iSocket->errorString(); log(err); emit socketError(err); return false; } } qRegisterMetaType<QAbstractSocket::SocketError>("SocketError" ); connect(iSocket, SIGNAL(disconnected()), this, SLOT(disconnected())); connect(iSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onErrors(QAbstractSocket::SocketError)), Qt::QueuedConnection); // If Server socket send Hello Message otherwise read it if (isServerSocket){ iSocket->write("Hello!\r\n"); } else { do { iSocket->waitForReadyRead(); } while (!iSocket->canReadLine()); QByteArray lineArr = iSocket->readLine(); log(lineArr.constData()); } log("> Client Connected"); emit connected(); return true; }
Now how they are stopped:
void InputConnection::readyRead() { if(iSocket->isOpen() && iSocket->canReadLine()){ QByteArray line = iSocket->readLine(); QString str("Data In: "); str += line; log(str); if(strcmp(line.constData(), "quit\r\n") == 0){ iOuputCon->closeConnection(); closeConnection(); } else { iOuputCon->getSocket()->write(line); // iSocket->write(line); } } } void InputConnection::closeConnection(){ Connection::closeConnection(); iSocket->disconnectFromHost(); } void InputConnection::disconnected() { log("> Disconnected"); emit closed(); }
And at higher level in the session how the connections are created/deleted:
SessionHandler::SessionHandler(qintptr aSocketDescriptor, MyThread *aThread, SessionManager *aSessionMgr): QObject(), iSocketDescriptor(aSocketDescriptor), iThread(aThread), iInCon(Q_NULLPTR), iOutCon(Q_NULLPTR), iSessionMgr(aSessionMgr) { #ifdef LOG_CONSTRUCTORS log("Constructor"); #endif iInCon = new InputConnection(iSocketDescriptor); iInCon->moveToThread(iThread); connect(this, &SessionHandler::startConnection, iInCon, &Connection::startTcpConnection); connect(iInCon, &Connection::connected, this, &SessionHandler::inputConnected); connect(iInCon, &InputConnection::closed, this, &SessionHandler::closeSession); connect(iInCon, &Connection::socketError, this, &SessionHandler::handleSocketError); } SessionHandler::~SessionHandler(){ #ifdef LOG_CONSTRUCTORS log("Destructor"); #endif delete iOutCon; delete iInCon; emit destroyed(); } void SessionHandler::inputConnected(){ log("TCP authentication done"); iOutCon = new OutputConnection(); iOutCon->startTcpConnection(cOutputHost, cOutputPort); iInCon->setOutput(iOutCon); iOutCon->setOutput(iInCon); iInCon->startAsyncRead(); iOutCon->startAsyncRead(); }
I'm getting this kind of output:
"[2015/12/13 23:39:10] [Thread -1258800832] Constructor" Server started, listening on port: 1111 "[2015/12/13 23:39:21] [Thread -1258800832] New incoming connection: 5" "[2015/12/13 23:39:21] [Thread -1258800832] Constructor" "[2015/12/13 23:39:21] [Thread -1258800832] SessionHandler[5] Constructor" "[2015/12/13 23:39:21] [Thread -1258800832] Connection[5] Constructor , serverSocket: 1" "[2015/12/13 23:39:21] [Thread -1258800832] InputConnection[5] Constructor" "[2015/12/13 23:39:21] [Thread -1258800832] [SessionManager] Connection Created: id=5, iSessions.size()=1" "[2015/12/13 23:39:21] [Thread -1260672192] InputConnection[5] Starting connection..." "[2015/12/13 23:39:21] [Thread -1260672192] InputConnection[5] > Client Connected" "[2015/12/13 23:39:21] [Thread -1260672192] SessionHandler[5] TCP authentication done" "[2015/12/13 23:39:21] [Thread -1260672192] Connection[0] Constructor , serverSocket: 0" "[2015/12/13 23:39:21] [Thread -1260672192] OutputConnection[0] Constructor" "[2015/12/13 23:39:21] [Thread -1260672192] OutputConnection[0] Starting connection..." "[2015/12/13 23:39:27] [Thread -1260672192] OutputConnection[0] hello\n" "[2015/12/13 23:39:27] [Thread -1260672192] OutputConnection[0] > Client Connected" "[2015/12/13 23:39:38] [Thread -1260672192] InputConnection[5] Data In: bye\r\n" "[2015/12/13 23:39:54] [Thread -1260672192] OutputConnection[0] Data In: bye\n" "[2015/12/13 23:39:58] [Thread -1260672192] InputConnection[5] Data In: quit\r\n" "[2015/12/13 23:39:58] [Thread -1260672192] InputConnection[5] > Disconnected" "[2015/12/13 23:39:58] [Thread -1260672192] SessionHandler[5] Closing SessionHandler" "[2015/12/13 23:39:58] [Thread -1260672192] [SessionManager] Connection Deleted: id=5, res: 1, iSessions.size()=0" "[2015/12/13 23:39:58] [Thread -1260672192] SessionHandler[5] Destructor" "[2015/12/13 23:39:58] [Thread -1260672192] OutputConnection[0] Destructor" "[2015/12/13 23:39:58] [Thread -1260672192] OutputConnection[0] Destructor (deleting iSocket)" "[2015/12/13 23:39:58] [Thread -1260672192] InputConnection[5] Destructor" "[2015/12/13 23:39:58] [Thread -1260672192] InputConnection[5] Destructor (deleting iSocket)" Press <RETURN> to close this window...
So basically, something is wrong on deletion...
I'm getting a segmentation fault and the error stack doesn't really help me...0 malloc_consolidate /usr/lib/debug/lib/i386-linux-gnu/i686/cmov/libc-2.19.so 4157 0xb6d69950 1 _int_malloc /usr/lib/debug/lib/i386-linux-gnu/i686/cmov/libc-2.19.so 3423 0xb6d6aba9 2 __libc_calloc /usr/lib/debug/lib/i386-linux-gnu/i686/cmov/libc-2.19.so 3219 0xb6d6d46f 3 g_malloc0 0xb4fbc736 4 g_slice_free1 0xb4fd43c6 5 g_thread_unref 0xb4fde6b2 6 ?? 0xb4fde6f8 7 __nptl_deallocate_tsd /usr/lib/debug/lib/i386-linux-gnu/i686/cmov/libpthread-2.19.so 157 0xb6ffcce6 8 start_thread /usr/lib/debug/lib/i386-linux-gnu/i686/cmov/libpthread-2.19.so 322 0xb6ffcf0e 9 clone /usr/lib/debug/lib/i386-linux-gnu/i686/cmov/libc-2.19.so 129 0xb6de062e
I'm not getting in the handler of QThread::finished so I suppose something gets wrong during the Thread destruction.
Please help.
you can find the whole project here: http://s000.tinyupload.com/?file_id=45521163106955445556basically, there is a constants.h where the ports are defined.
const unsigned short cServerPort = 1111; const unsigned short cOutputPort = 2222; constexpr char* cOutputHost = "localhost";
So the easiest way to test it and see the crash is to :
- launch a netcat on a terminal to simulate the output. (nc -l 2222)
- launch the proxy
- telnet localhost 1111 (to simulate a client)
then from the netcat shell write something,
- write: quit on the telnet to shutdown the session
Sorry to give the whole program to debug but I'm pretty stuck and have no clue what is going wrong...
Thanks in advance :) -
Hello,
That is a lot of code, and don't see (at a glance) anything wrong. You might be getting a race condition or a double-delete (my guess) at some point, but this should be traced through the debugger. Is this your whole stack trace (the provided one), it looks pretty thin? -
@kshegunov
well that was just the stack trace inside the stack view of QT creator.
Here is the full version:Thread 2 (Thread 0xb4cf8b40 (LWP 9517)): #0 0xb6d2d950 in malloc_consolidate (av=av@entry=0xb4300010) at malloc.c:4157 fb = 0xb4300024 maxfb = 0xb430003c p = 0xb4303137 nextp = 0x30d67000 unsorted_bin = 0xb4300040 first_unsorted = <optimized out> nextchunk = 0xb4305e37 size = 11520 nextsize = 0 prevsize = <optimized out> nextinuse = <optimized out> bck = 0x1b4 fwd = 0x30d67000 __func__ = "malloc_consolidate" #1 0xb6d2eba9 in _int_malloc (av=av@entry=0xb4300010, bytes=bytes@entry=2040) at malloc.c:3423 nb = 2048 idx = 88 bin = <optimized out> victim = <optimized out> size = <optimized out> victim_index = <optimized out> remainder = <optimized out> remainder_size = <optimized out> block = <optimized out> bit = <optimized out> map = <optimized out> fwd = <optimized out> bck = <optimized out> errstr = 0x0 __func__ = "_int_malloc" #2 0xb6d3146f in __libc_calloc (n=1, elem_size=2040) at malloc.c:3219 av = 0xb4300010 oldtop = 0xb431e020 p = <optimized out> bytes = 2040 sz = 2040 csz = <optimized out> oldtopsize = 36832 mem = <optimized out> clearsize = <optimized out> nclears = <optimized out> d = <optimized out> hook = <optimized out> __func__ = "__libc_calloc" #3 0xb4f80736 in g_malloc0 () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available. #4 0xb4f983c6 in g_slice_free1 () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available. #5 0xb4fa26b2 in g_thread_unref () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available. #6 0xb4fa26f8 in ?? () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available. #7 0xb6fc0ce6 in __nptl_deallocate_tsd () at pthread_create.c:157 data = 0x30d67000 inner = 3 cnt = 3033500648 #8 0xb6fc0f0e in start_thread (arg=0xb4cf8b40) at pthread_create.c:322 pd = 0xb4cf8b40 now = <optimized out> unwind_buf = {cancel_jmp_buf = {{jmp_buf = {-1224921088, -1261466816, 4001536, -1261468632, 1235077839, 780581579}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} not_first_call = <optimized out> pagesize_m1 = <optimized out> sp = <optimized out> freesize = <optimized out> __PRETTY_FUNCTION__ = "start_thread" #9 0xb6da462e in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:129 No locals. Thread 1 (Thread 0xb4ec1940 (LWP 9506)): #0 0xb76e3d40 in __kernel_vsyscall () No symbol table info available. #1 0xb6d99deb in poll () at ../sysdeps/unix/syscall-template.S:81 No locals. #2 0xb4f8a0b0 in g_poll () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available. #3 0xb4f7b054 in ?? () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available. #4 0xb4f7b196 in g_main_context_iteration () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available. #5 0xb72cbda4 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /opt/Qt5.5.1/5.5/gcc/lib/libQt5Core.so.5 No symbol table info available. #6 0xb7271d13 in QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /opt/Qt5.5.1/5.5/gcc/lib/libQt5Core.so.5 No symbol table info available. #7 0xb727218a in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from /opt/Qt5.5.1/5.5/gcc/lib/libQt5Core.so.5 No symbol table info available. #8 0xb727a28a in QCoreApplication::exec() () from /opt/Qt5.5.1/5.5/gcc/lib/libQt5Core.so.5 No symbol table info available. #9 0x0804a3c5 in main (argc=1, argv=0xbfca6cc4) at ../Proxy/main.cpp:15 a = <incomplete type> proxy = {<QTcpServer> = {<No data fields>}, static staticMetaObject = {d = {superdata = 0xb76dd6c4 <QTcpServer::staticMetaObject>, stringdata = 0x8051340 <qt_meta_stringdata_Proxy>, data = 0x80513c0 <qt_meta_data_Proxy>, static_metacall = 0x804f640 <Proxy::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)>, relatedMetaObjects = 0x0, extradata = 0x0}}, iSessionMgr = 0x8c58490} __PRETTY_FUNCTION__ = "int main(int, char**)"
But it doesn't really talks to me...
From my log traces I can see that all the allocated objects are destructed properly. What should follows is just the thread quit and then destruction...
Before adding the second socket to the outside (just 1 input socket where I was echoing the requests) it was working.
I'm wondering if it could be something relating to the event loop... maybe having some in queue but the object getting deleted? -
Hello,
Indeed the stack trace is not very helpful. I've started your program on my computer, and It pretty much works fine. I pushed a hello string through telnet. Here's the output:"[2015/12/14 07:43:10] [Thread 140640749758272] Constructor" Server started, listening on port: 1111 "[2015/12/14 07:44:00] [Thread 140640749758272] New incoming connection: 7" "[2015/12/14 07:44:00] [Thread 140640749758272] Constructor" "[2015/12/14 07:44:00] [Thread 140640749758272] SessionHandler[7] Constructor" "[2015/12/14 07:44:00] [Thread 140640749758272] Connection[7] Constructor , serverSocket: 1" "[2015/12/14 07:44:00] [Thread 140640749758272] InputConnection[7] Constructor" "[2015/12/14 07:44:00] [Thread 140640749758272] [SessionManager] Connection Created: id=7, iSessions.size()=1" "[2015/12/14 07:44:00] [Thread 140640676415232] InputConnection[7] Starting connection..." "[2015/12/14 07:44:00] [Thread 140640676415232] InputConnection[7] > Client Connected" "[2015/12/14 07:44:00] [Thread 140640676415232] SessionHandler[7] TCP authentication done" "[2015/12/14 07:44:00] [Thread 140640676415232] Connection[0] Constructor , serverSocket: 0" "[2015/12/14 07:44:00] [Thread 140640676415232] OutputConnection[0] Constructor" "[2015/12/14 07:44:00] [Thread 140640676415232] OutputConnection[0] Starting connection..." "[2015/12/14 07:44:01] [Thread 140640676415232] OutputConnection[0] connecting to host: localhost:2222. socket error: Connection refused" "[2015/12/14 07:44:07] [Thread 140640676415232] InputConnection[7] Data In: hello " "[2015/12/14 07:44:14] [Thread 140640676415232] InputConnection[7] Data In: quit " "[2015/12/14 07:44:14] [Thread 140640676415232] InputConnection[7] > Disconnected" "[2015/12/14 07:44:14] [Thread 140640676415232] SessionHandler[7] Closing SessionHandler" "[2015/12/14 07:44:14] [Thread 140640676415232] [SessionManager] Connection Deleted: id=7, res: 1, iSessions.size()=0" "[2015/12/14 07:44:14] [Thread 140640676415232] SessionHandler[7] Destructor" "[2015/12/14 07:44:14] [Thread 140640676415232] OutputConnection[0] Destructor" "[2015/12/14 07:44:14] [Thread 140640676415232] OutputConnection[0] Destructor (deleting iSocket)" "[2015/12/14 07:44:14] [Thread 140640676415232] InputConnection[7] Destructor" "[2015/12/14 07:44:14] [Thread 140640676415232] InputConnection[7] Destructor (deleting iSocket)" "[2015/12/14 07:44:14] [Thread 140640749758272] Destructor" "[2015/12/14 07:44:14] [Thread 140640749758272] Thread deleted"
Notice that the connection on port 2222 fails, as I don't have anything listening on that port, and I'm not sure what is supposed to be there. Maybe look at that part of the code (the output connection part).
Hope this helps.
-
on what environment are you running it? I'm on linux 3.16 x86.
I've tried like you, without anything listening on the output on port 2222 and it is crashing also kind of the same way.
Here is the full stack:Thread 3 (Thread 0xb43ffb40 (LWP 3124)): #0 0xb7020094 in start_thread (arg=0xb43ffb40) at pthread_create.c:358 idx = 0 mask = 256 pd = 0xb43ffb40 now = <optimized out> unwind_buf = {cancel_jmp_buf = {{jmp_buf = {-1224531968, -1270875328, 4001536, -1270877144, -197850265, -2010219679}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} not_first_call = <optimized out> pagesize_m1 = <optimized out> sp = <optimized out> freesize = <optimized out> __PRETTY_FUNCTION__ = "start_thread" #1 0xb6e0362e in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:129 No locals. Thread 2 (Thread 0xb4d57b40 (LWP 3123)): #0 0xb6d8c950 in malloc_consolidate (av=av@entry=0xb4400010) at malloc.c:4157 fb = 0xb4400024 maxfb = 0xb440003c p = 0xb440683f nextp = 0x40313800 unsorted_bin = 0xb4400040 first_unsorted = <optimized out> nextchunk = 0xb441043f size = 39936 nextsize = 0 prevsize = <optimized out> nextinuse = <optimized out> bck = 0x0 fwd = 0x0 __func__ = "malloc_consolidate" #1 0xb6d8dba9 in _int_malloc (av=av@entry=0xb4400010, bytes=bytes@entry=2040) at malloc.c:3423 nb = 2048 idx = 88 bin = <optimized out> victim = <optimized out> size = <optimized out> victim_index = <optimized out> remainder = <optimized out> remainder_size = <optimized out> block = <optimized out> bit = <optimized out> map = <optimized out> fwd = <optimized out> bck = <optimized out> errstr = 0x0 __func__ = "_int_malloc" #2 0xb6d9046f in __libc_calloc (n=1, elem_size=2040) at malloc.c:3219 av = 0xb4400010 oldtop = 0xb4411f38 p = <optimized out> bytes = 2040 sz = 2040 csz = <optimized out> oldtopsize = 61640 mem = <optimized out> clearsize = <optimized out> nclears = <optimized out> d = <optimized out> hook = <optimized out> __func__ = "__libc_calloc" #3 0xb4fdf736 in g_malloc0 () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available. #4 0xb4ff73c6 in g_slice_free1 () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available. #5 0xb50016b2 in g_thread_unref () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available. #6 0xb50016f8 in ?? () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available. #7 0xb701fce6 in __nptl_deallocate_tsd () at pthread_create.c:157 data = 0x0 inner = 3 cnt = 3033889768 #8 0xb701ff0e in start_thread (arg=0xb4d57b40) at pthread_create.c:322 pd = 0xb4d57b40 now = <optimized out> unwind_buf = {cancel_jmp_buf = {{jmp_buf = {-1224531968, -1261077696, 4001536, -1261079512, 557124454, -2010219679}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} not_first_call = <optimized out> pagesize_m1 = <optimized out> sp = <optimized out> freesize = <optimized out> __PRETTY_FUNCTION__ = "start_thread" #9 0xb6e0362e in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:129 No locals. Thread 1 (Thread 0xb4f20940 (LWP 3113)): #0 0xb7742d40 in __kernel_vsyscall () No symbol table info available. #1 0xb6df8deb in poll () at ../sysdeps/unix/syscall-template.S:81 No locals. #2 0xb4fe90b0 in g_poll () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available. #3 0xb4fda054 in ?? () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available. #4 0xb4fda196 in g_main_context_iteration () from /lib/i386-linux-gnu/libglib-2.0.so.0 No symbol table info available. #5 0xb732ada4 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /opt/Qt5.5.1/5.5/gcc/lib/libQt5Core.so.5 No symbol table info available. #6 0xb72d0d13 in QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /opt/Qt5.5.1/5.5/gcc/lib/libQt5Core.so.5 No symbol table info available. #7 0xb72d118a in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from /opt/Qt5.5.1/5.5/gcc/lib/libQt5Core.so.5 No symbol table info available. #8 0xb72d928a in QCoreApplication::exec() () from /opt/Qt5.5.1/5.5/gcc/lib/libQt5Core.so.5 No symbol table info available. #9 0x0804a3c5 in main (argc=1, argv=0xbf8a82b4) at ../Proxy/main.cpp:15 a = <incomplete type> proxy = {<QTcpServer> = {<No data fields>}, static staticMetaObject = {d = {superdata = 0xb773c6c4 <QTcpServer::staticMetaObject>, stringdata = 0x8051340 <qt_meta_stringdata_Proxy>, data = 0x80513c0 <qt_meta_data_Proxy>, static_metacall = 0x804f640 <Proxy::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)>, relatedMetaObjects = 0x0, extradata = 0x0}}, iSessionMgr = 0x9e30490} __PRETTY_FUNCTION__ = "int main(int, char**)"
I'm not sure why there are 3 threads...
Are you sure it is not crashing for you? Can you telnet again 1111 and interact with the proxy a second time? -
otherwise on port 2222, there should only be a simple TCP socket that should first send on "Hello\r\n" message when the connection is established and then act as an echo server.
An easy way is to use netcat on a terminal in listening mode: netcat -l 2222
in another one, you run the telnet localhost 1111
you then need to go to the netcat to write the hello to unblock the telnet.
then from the telnet you can write whatever, reply from netcat.
and quit from the telnet. -
I found the issue...
QT doesn't like object suicide from its own slot...
basically I was triggering the own deletion of SessionHandler in the slot connectionClose() doing the equivalent of a "delete this" to call the destructor.
I've changed it by emitting a signal to himself that is connected to deleteLater.
In this way it doesn't mess up the event queue :)
Cool!
I was trying to avoid using signal when not necessary for performance issues but I may change my mind... -
@mbruel
Hello,
I'm running Debian stretch on a 4.2.1 kernel (Qt 5.5.1). It is strange that deleting itself would cause that, but maybe there are some subtle differences between platforms. Still, like Qt, I don't much like the "commit suicide" approach, I firmly believe it's not a good practice. Anyway, I'm glad it worked out in the end.As a side note, signals and slots are fast enough for pretty much anything I've come with, so trying to avoid them on basis of "speed" is a low-level optimization that is very, very premature.
Kind regards.
-
haha, yeah obviously the suicide approach is not a good practice but it was not a straight suicide, rather asking for euthanasia.
In term of design pattern, I find it fine because my SessionHandler warn the SessionManager that is the good time to destroy it. I like the fact that the SessionManager owns all the Sessions and is responsible for both creation and deletion.
Here was the code:void SessionHandler::closeConnection(){ if (isActive){ log("closeConnection SessionHandler"); isActive = false; iInputCon->closeConnection(); iSessionMgr.delSession(this); emit deleteSession(); } } bool SessionManager::delSession(SessionHandler *aInputTh){ QMutexLocker lock(&mMutex); bool out = iSessions.removeOne(aInputTh); QString str("Connection Deleted: id="); str += QString::number(aInputTh->id()); str += ", res: "; str += QString::number(out); log(str); delete aInputTh; return out; }
So in the fact it's kind of equivalent to a suicide:
void SessionHandler::closeConnection(){ if (isActive){ log("closeConnection SessionHandler"); isActive = false; iInputCon->closeConnection(); delete this; emit deleteSession(); } }
but it is clear that no one will use the SessionHandler anymore so shouldn't be dangerous. In term of global design I think I prefer this approach than relying on the event loop of the Thread. But I'm porting an application done in Java where there are not this kind of issue as there are no destructors... Instead we would just use a close function to close all the open resourced (socket, stream...)
What do you think, still something to avoid? I guess in async programming it is but in pure C++ I could still consider this approach.I'm using debian wheezy. Weird indeed that the behaviour was not the same than on yours. Anyway, I understand that this could be problematic for the event queue and that it is cleaner to use a deleteLater and have no suicide or euthanasia... haha
For speed optimisation and avoiding signal/slots when possible, well I don't know... I'm new to async programming and still don't really see the point to use a signal/slot mechanism with direct connection instead of directly calling the function on the object. It might not optimize a lot but it should definitely avoid few functions calls and passing by the event queue.
Just to let you know, I've not finished my program, far from it but I did enough to be able to test the performances of the core proxy (bandwidth, cpu usage). I'm quite amazed!
I'm using an SSL connection in the input, an SSL connection in the output so decoding and reencoding on the fly.
With my Java version, with 4 Threads I could get only a bandwidth of 22Mb/s and with the QT version I arrive to 72Mb/s. (knowing that directly on the output the bandwidth would be 100Mb/s). That's more than 3 times better!!! I'm so happy, I wasn't hoping for such an improvement!
Well, the java version is using blocking sockets. That could be the reason of such a difference. I'm wondering if the impressive results of the QT version are due to the C++ and use of native socket or more of the non blocking sockets. What do you think? -
@mbruel said:
What do you think, still something to avoid?
You do want to free your resources, while this is usually done in the destructor, that might not always be the case (for example
QFile
hasopen()
andclose()
methods, and internal state that it tracks.For speed optimisation and avoiding signal/slots when possible, well I don't know... I'm new to async programming and still don't really see the point to use a signal/slot mechanism with direct connection instead of directly calling the function on the object. It might not optimize a lot but it should definitely avoid few functions calls and passing by the event queue.
When you connect objects that live in the same thread, you don't have any event queue calls (it's a direct connection, and behaves exactly like you've invoked the function yourself). A reason why you might want to use signals and slots, instead of pure function calls is to decouple components, which is something you'd want for the most part.
I'm wondering if the impressive results of the QT version are due to the C++ and use of native socket or more of the non blocking sockets.
Probably both, although internally (at the OS level) the sockets are blocking, you just don't see it. Also linux sockets, at least to my experience, tend to perform better than their windows counterparts. I don't know why, they just seem to be faster.