i have a tcp server, which requires to allow exactly one client to connect to it at any time. anytime a new client connects, older session must be deleted and new session created.
right now, i am doing it like this:
void TcpServer::start_accept() {
Logger::info("[TCPSERVER] TCP Server starting to accept", __LINE__, __FILE__);
if (session) { // check if there is any older session, if so..delete them
session = NULL;
delete session;
}
session = new TcpServerSession(io_service_);
acceptor_.async_accept(session->socket(), boost::bind(&TcpServer::handle_accept, this, session, boost::asio::placeholders::error));
}
so any time i would like to send a msg to the client, it is being done like this:
int TcpServer::sendMsgToClient(std::string msg) {
if (session)
session->sendMsgToClient(msg);
}
i am wondering if this is being done correctly? basically the main point is deleting a pointer and re-creating it.whats the best way to do this?
Just use a std::unique_ptr<> :
session.reset(new TcpServerSession(io_service_));
It gets everything right: don't delete old object before a new one is available, never have session point to something invalid, and even in the presence of exceptions no memory is leaked.
if (session) { // check if there is any older session, if so..delete them
session = NULL;
delete session;
}
This is totally wrong! You blank out session, leaking whatever is currently there, and then delete NULL, which does absolutely nothing.
To be exception safe, you should not delete the old session until you have successfully created the new one. Something like this:
if (session) {
// Create and initialise the new session first
TcpServerSession* newSession = new TcpServerSession(io_service_);
// Don't know what this line does, but I assume it's important
acceptor_.async_accept(newSession->socket(), boost::bind(&TcpServer::handle_accept, this, newSession, boost::asio::placeholders::error));
std::swap(session, newSession); // Put the new one in place
delete newSession; // delete the old one.
}
Actually, this assumes async_accept doesn't throw. If it can, you will need to be careful to delete the newSession, probably with some kind of smart pointer.
session = NULL;
delete session;
Is most certainly not correct. If you replace the value that session holds (which points to a block of memory allocated by new) before calling delete on it, you effectively lose that block of memory, causing a memory leak. The only reason why this code doesn't blow up is because calling delete with a NULL is guaranteed to be a no-op.
Thus, you should replace the code with the following :
delete session;
session = NULL; // or nullptr if you've got C++11
Which will guarantee that the memory is properly freed.
Get rid of session = NULL before delete session. You're trying to delete the null pointer.
You don't need to set it to null because you're immediately going to set it to the new TCP session.
if (session) { // check if there is any older session, if so..delete them
session = NULL;
delete session;
}
This code says:
If session points to some valid object (instead of being null), then stop pointing to it (instead, point to NULL), and then delete what session now points to, i.e. delete nothing.
This is very bad. It is a genuine memory leak.
The comment is a lie.
Related
I try to use QTcpSserver, which would keep connection with one and only one client at a time, until the client disconnects. So, I keep the client with a member pointer in my class.
The problem arises here: In the examples I see on the internet, after disconnected(), it is called deleteLater(). Good, but I would use this class-member pointer again for another connection. Remember that the server keeps one and only one client at a time. So, what if the socket object is deleted after another connection assigned on it?
What I mean is:
class TcpServer(QObject* o) : public QTcpServer {
...
private:
QTcpSocket* client;
}
void TcpServer::connected() {
client = this->nextPendingConnection();
this->pauseAccepting();
connect(client, SIGNAL(disconnected()), client, SLOT(clientDisconnected()));
}
void TcpServer::clientDisconnected() {
client->deleteLater();
this->resumeAccepting();
}
Scenario is this:
Client connected. So, client = nextPendingConnection();
Server paused listening. Does not accept new connection.
Client is disconnected. client needs to be released. So, client->deleteLater() is calleed.
Server continues listening.
New connection comes. So, I need to client = nextPendingConnection();
But, previous client object was deleted? Maybe? Maybe not? What if event loop tries to delete client, after I have assigned the new connection to it in step 5?
So, how would I keep one and only one client, while deleting previous disconnected ones?
Would it be safe if I do this?
void TcpServer::clientDisconnected()
{
QSocket* ptr = client;
ptr->deleteLater();
...
}
I will cite Qt documentation about it:
The object will be deleted when control returns to the event loop.
So deleteLater() is a delayed delete. The object is to be regarded as deleted as soon as the call deleteLater() was made.
Your nextPendingConnection() call will create another object that need to be deleted some time later.
However in your case you only allow one pending connection as you said and disallow accepting until client gets disconnected. I this case it should be safe, in other cases you could overwrite your client pointer and will lose control over it (memory leak).
Even in your case, I would prefer this solution:
void TcpServer::clientDisconnected()
{
if (qobject_cast<QAbstractSocket*>(sender())) {
sender()->deleteLater();
}
...
}
This would also be safe if more than one connection is allowed in future changes of your application.
As i understand nextPendingConnection(); will return pointer to new QTcpSocket class object so you have nothing to worry about.
deleteLater() will scheduled for deletion only your old object. QTcpSocket* client contains only pointer to QTcpSocket class object. When you calling deleteLater() Qt will delete only object to which client was pointed at time of calling this function.
So i just programmed a simple multithreaded client server application using winsock2 and TCP.
Here is a quick summary of how it works:
The servers main-thread is in a endless loop accepting clients and then also adding them to the servers vector which holds every connected client like this:
(only adding in the important stuff for my question)
std::vector <Client*> clients;
while (true){
clients.push_back(&Client(accept(serverSocket, NULL, NULL), this));
}
When a new client connects to the server we basically create a new Client object with the socket of the new client and the server itself as parameters.
My idea was then to give every client its own thread so every client can send data at the same time.
std::thread tickThread;
Client::Client(SOCKET socket,Server* server) :
isConnected(true),
socket(socket),
server(server)
{
tickThread = std::thread(&Client::tick,this);
}
The thread for the client then checks if the client sent something and then sends it to the server. It also checks wether the client is still connected.
void Client::tick(){
while (isConnected){
errorHandler = recv(socket, receivedData, 255, 0);
if (errorHandler == SOCKET_ERROR){
disconnect();
}
else {
//send received data to server
}
}
If the client disconnected it tells the server to remove the client from the connected clients vector and then sets the "isConnected" bool to false so the thread can exit its function.
void Client::disconnect(){
isConnected = false;
server->removeClient(this);
}
This is how it's supposed to work, however as soon as a client disconnects again the server crashes with the error:
R6010 - abort() has been called
All debugging shows me is this as my error:
switch (_CrtDbgReportW(_CRT_ERROR, NULL, 0, NULL, L"%s", error_text)){
case 1: _CrtDbgBreak(); msgshown = 1; break;
case 0: msgshown = 1; break;
}
So yeah i don't really know whats causing this crash, however i suspect that it might be related to the thread using a function of the client that's basically being deleted as it is being removed from the client vector of the server.
And if this turns out to be the problem could you guys give me ideas for a better way of implementing every client having its own thread?
Edit: changed the vector error, however the crash still happens as soon as a client disconnects
The error is in this block of code:
while (true){
clients.push_back(&Client(accept(serverSocket, NULL, NULL), this));
}
Client(accept(serverSocket, NULL, NULL), this) is an expression which generates a temporary Client object that is destroyed when the statement finishes executing. However, you take the address of that temporary object and add it to your vector.
If you want to create Client objects and store pointers to them, you will need to allocate memory for them. I would recommend using std::unique_ptr to manage them so that your vector claims ownership of their memory and automatically frees them if they are removed from the vector or the vector itself is destroyed. Then your code becomes:
std::vector<std::unique_ptr<Client>> clients;
while (true){
clients.push_back(std::make_unique<Client>(accept(serverSocket, NULL, NULL), this));
}
In this piece of code:
clients.push_back(&Client(accept(serverSocket, NULL, NULL), this));
You are pushing an address of a temporary object into the container. When push_back() is done, the temporary object is destroyed, so that address is no longer valid. I wonder, what kind of compiler allows you to do this.
I used one scene and many layers for my game.
when user go to another game screen I remove current layer from scene , delete current layer, set current layer = NULL, then create a new layer, add it to the scene
void UIManager::openScreen(int screenId){
m_currentScreen = screenId;
CCLayer *newLayer;
if(screenId == MENU_SCREEN){
newLayer = new MenuLayer();
}else{
...
}
if(m_currentLayer != NULL){
m_scene->removeChild(m_currentLayer, true);
delete m_currentLayer;
m_currentLayer = NULL;
}
m_scene->addChild(newLayer);
m_currentLayer = newLayer;
}
On some layers, i call some CCHttpRequest with callback:
setResponseCallback(CCObject* pTarget, SEL_CallFuncND pSelector)
And i use "this" to pass to "pTarget", it means first parameter for this callback is my layer which defined a SEL_CallFuncND selector.
The problem is when user switch between screens(layers) to quick, but some slow CCHttpRequest still not completed, and the response callback will be called after UIManager delete the layer then my game crash :(. I don't want to lock the screen and force use wait the http request complete. User should can abort loading a screen and switch to the next screen they want.
So should i call "delete m_currentLayer" instead of m_currentLayer->release()?
As i know, release will decrease the reference count, i just want to make sure "noone" use the m_currentLayer rather than m_scene so i used "delete". But i'm not sure it is correct way.
If i use release function in this case, i worry some places in code use the layer and increase the retain count of the layer, is this can make a leak memory issue?
if m_currentLayer->retainCount() = 4 and i call "delete m_currentLayer", then what will happen with m_currentLayer?
I'm confusing with these issues, please someone give me an advide.
Thank you very much!
You should not delete your nodes manually. It can cause a bunch of errors. Reference
counting convention is to call retain when you need to be sure that object still exists and call release when you do not need this object.
Use retain and release only inside object, that really needs other object to exist. In any other case you can use assign property(do not retain object and check it is not NULL) before doing something with it. If some object(let's call it a), that is not yours(CCNode, for example) retains the other object(let's call it b), deleting b manually can cause bad access error, because a will be sure that b still exists. And can call something like b->doSmth()
Your m_currentLayer will be deleted, but it can cause errors because retain count 4 means that 4 objects can cause bad access error described above.
I am sending an HTTP request to save/update data on the server. The request is made asynchronously and a callback function is called when it completes. Everything works fine except that sometimes, the application crashes in the callback.
This is what I am doing:
user = new User();
user->saveOnServer();
user->zombie = true; // Mark the user that it needs to be deleted in the callback.
In User, I have a saveOnServer() method:
void User::saveOnServer(){
Request *request = new Request();
// Send request to the server and register the callback.
request ->setCallback(&userCallback, (void*)this);
}
The callback:
void userCallback(void *data){
User *user = (User*)data;
// Do something here.
// Delete user if it's a zombie.
if(user->zombie)
delete user;
}
At times, I need to create a new user after sending a request to the server:
user = new User();
user->saveOnServer();
user->zombie = true;
// Some code comes here.
if(user)
delete user;
user = new User();
The problem is that in such cases, the application crashes when deleting the user in the callback as it has already been deleted. Another issue is that the callback deletes user but user pointer in main is still pointing to some address (dangling pointer) and so I again try to delete it.
I am not sure what is the best way of managing memory in this case. I have zombie in place because there are cases when I do not want the callback to delete the user.
Once you've called saveOnServer of a zombie user, the request is the effective "owner" of that user object. Don't free it yourself since there's something else that still intends to use it and delete it later.
In fact, if the server action can return asynchronously, then the user object might get destroyed at any time. You should cease using it entirely from the other code. You've granted control of that object to the request, and you must stop using it from anywhere else:
user = new User();
user->zombie = true; // set *before* transferring ownership to server
user->saveOnServer();
user = NULL;
//some code comes here
user = new User();
If you don't want the request to use that object anymore, then you need to provide some facility for "canceling" the save-on-server action so that it doesn't use the object.
Another option is to use smart pointers. In your main code, store the object in a shared_ptr. In the request object, store it in a weak_ptr. That way, if your main code wants to destroy the user object, it can simply call user.reset(). Then if the callback attempts to use the weak_ptr, it will discover that the pointed-to object is no longer available. When using smart pointers, neither function should use delete. The pointer objects will manage the lifetime of the user for you.
shared_ptr<User> user = make_shared<User>()
user->saveOnServer();
//some code comes here
user.reset(new User());
In the saveOnServer function, use shared_from_this to create a weak_ptr to the object:
void User::saveOnServer(){
Request *request = new Request();
//send request on server and register the callback
weak_ptr<User> self(shared_from_this());
request ->setCallback(&userCallback, self);
}
In the callback, use that weak_ptr:
void userCallback(weak_ptr<User> data){
shared_ptr<User) user = data.lock();
if (!user)
return;
//do something here
}
I'm programming an application that uses QUdpSockets.
As I'm getting memory problems due to creating sockets with the operator new I would like to know if it is necesary to delete them after closing it.
Code below:
socket = new QUdpSocket(this);
socket->bind();
connect(socket, SIGNAL(readyRead()), this, SLOT(getResponse()));
socket->close();
delete socket; //Do I have to do this to free the mem?
Help will be thanked.
Depends on what this is. Whenever that gets destroyed, the QUdpSocket will be too.
As soon as you don't need the socket anymore you can call :
socket->deleteLater();
And yes, it's better to destroy the socket when you don't need it anymore.
An other solution is to delete 'this', so socket will be also deleted.
If your done with the socket you should delete it. This way you are on the safe side. Also it doesnt hurt. However as it was already pointed out "this" will take for the destruction of the socket (see http://doc.qt.io/qt-4.8/qobject.html#QObject ).