最近在用QtNetwork編寫服務器程序進行TCP/IP通信,大體過程如下:
1. 創建一個QTcpServer實例,監聽目標IP和端口;
2. 一旦監聽到有連接,獲取和客戶端之間的socket;
3. 使用socket進行通信;
4. 通信結束后,可以手動釋放socket,也可以不管它,在釋放QTcpServer的時候會把其下的所有socket全部自動釋放。
在編寫時,我做了如下事:
- TcpNetwork::TcpNetwork()
- {
- ...
- connect(mySocket, SIGNAL(disconnect(QTcpSocket*)), this, SLOT(ServerConnectionLost(QTcpSocket*)));
- ...
- }
- TcpNetwork::~TcpNetwork()
- {
- if (tcpServer != NULL)
- {
- delete tcpServer;
- }
- }
- <pre name="code" class="cpp">void TcpNetwork::ServerConnectionLost(QTcpSocket *socket)
- {
- if (socket == mySocket)
- {
- ...
- // debug
- delete mySocket;
- mySocket = NULL;
- ...
- }
- }
這樣在關閉程序窗口時會導致崩潰,看了一下QTcpServer的析構函數源碼后發現,在析構時Qt會首先檢查QtcpServer下的socket指針所指向內存是否已被釋放,然后執行每個socket的關閉操作,隨后釋放剛才被檢查過的未被釋放的socket內存,最后釋放QTcpServer。
如果將QTcpSocket::disconnect()信號與一個其中帶有釋放socket操作的槽連接起來,那么如果socket還沒有關閉就直接析構QTcpServer,在執行斷開socket這一步時(如果之前已經斷開了就不會再執行這一步了)會觸發帶有刪除socket操作的槽,然而析構函數對此一無所知,緊接着便是析構函數來釋放socket,也就造成了socket的內存的重復釋放,導致崩潰。
解決方法:在關閉窗口之前先關閉socket,這樣在析構函數中就不會再執行關閉socket的操作。或者在連接斷開時觸發的含有釋放socket操作的槽中將delete socket改為socket->deleteLater()。
http://blog.csdn.net/qq_19672579/article/details/47973409