QTcpSocket-Qt使用Tcp通信實現服務端和客戶端

版權聲明:若無來源註明, Techie亮博客文章均爲原創。 轉載請以連接形式標明本文標題和地址:
本文標題:QTcpSocket-Qt使用Tcp通信實現服務端和客戶端     本文地址: https://www.techieliang.com/2017/12/530/

1. 基本功能

詳細說明請見官方文檔html

1.1. pro文件配置

使用Qt網絡功能須要在pro文件增長網絡庫服務器

  1. QT += network

1.2. QTcpServer服務端創建

  1. QTcpServer server = new QTcpServer();
  2. connect(server,
  3. &QTcpServer::newConnection,
  4. this,
  5. &MainWindow::server_New_Connect);//監聽
  6. if(!server->listen(QHostAddress::Any, 8000)) {
  7. qDebug()<<server->errorString(); //錯誤信息
  8. }

建立server對象之後首先要監聽客戶端的鏈接,經過listen函數能夠開啓監聽,須要指定監聽的ip和端口號,ip可以使用QHostAddress::Any網絡

QTcpServer當有新客戶端鏈接時會發出QTcpServer::newConnection的信號,只須要關聯到自定義的槽便可。app

  1. void MainWindow::server_New_Connect() {
  2. //獲取客戶端鏈接
  3. auto socket_temp = server->nextPendingConnection();//根據當前新鏈接建立一個QTepSocket
  4. m_socket=socket_temp;//記錄此鏈接用於後續數據讀寫
  5. //鏈接QTcpSocket的信號槽,以讀取新數據
  6. QObject::connect(socket_temp, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data);
  7. //當斷開鏈接時發出的信號
  8. QObject::connect(socket_temp, &QTcpSocket::disconnected, this, &MainWindow::socket_Disconnected);
  9. }

上述爲一個新鏈接到來的槽函數範例,利用nextPendingConnection獲取到新鏈接的socket,存儲此socket,並關聯對應的信號socket

主要有兩個:接收到新數據的信號以及鏈接斷開的信號。函數

當鏈接斷開能夠經過響應信號槽機制實現斷開後的操做。this

1.3. 客戶端創建

客戶端爲主動鏈接方,不須要監聽,直接創建QTcpSocket便可spa

  1. m_socket = new QTcpSocket;
  2. m_socket->connectToHost("127.0.0.1",80100,QTcpSocket::ReadWrite);
  3. connect(m_socket,SIGNAL(connected()),this,SLOT(connected()));

上述例子使用的是信號槽方式等待鏈接成功,也可使用阻塞方式:waitForConnected,等到鏈接成功纔會執行後續代碼,不須要創建新的槽函數。server

經過connectToHost鏈接指定ip和端口,同時將socket的鏈接成功的信號與對應槽鏈接,當鏈接成功能夠將自定義的標記位置爲true,可進行相應的收發。htm

  1. void MainWindow::connected() {
  2. m_is_connected = true;
  3. connect(this->socket,SIGNAL(readyRead()),this,SLOT(readyread())); //鏈接接收消息槽
  4. QObject::connect(socket_temp,?&QTcpSocket::disconnected,?this,?&MainWindow::socket_Disconnected);//斷開鏈接
  5. }

當鏈接成功建議將接收和斷開鏈接的信號進行connect

1.4. 消息收發

  • 不阻塞收發:

不管客戶端仍是服務端只有在創建鏈接時有差別,後續的消息收發都相同。

首先經過QTcpSocket::close()能夠主動斷開鏈接,不管客戶端服務端均可以執行主動斷開

經過readyRead()信號能夠在接到信息後進行信息操做,在槽中執行QTcpSocket::readAll()能夠讀取緩衝區全部數據

QTcpSocket::send()可發送信息,調用flush可當即發送緩衝區的數據,不需等待。

  • 阻塞收發:

Qt同時提供了阻塞收發及鏈接、斷開鏈接的函數:

virtual bool waitForConnected(int msecs = 30000)
virtual bool waitForDisconnected(int msecs = 30000)
virtual bool waitForBytesWritten(int msecs = 30000)
virtual bool waitForReadyRead(int msecs = 30000)

經過上述函數能夠實現阻塞鏈接、斷開鏈接、發送、接收數據內容

2. 其餘

2.1. 實現單服務器多客戶端通信

網上大部分例子都是單服務器通信,若不作修改鏈接多個客戶端,會出現只有最後一個通信有效的狀況。

主要緣由是在監聽到新鏈接時的處理方式不當:

  1. connect(server, &QTcpServer::newConnection, this, &MainWindow::server_New_Connect);//監聽
  2. if(!server->listen(QHostAddress::Any, 8000)) {
  3. qDebug()<<server->errorString(); //錯誤信息
  4. }

注意上述代碼在服務端收到信鏈接時會固定的調用一個槽函數,而槽函數每每寫成下述樣式:

  1. void MainWindow::server_New_Connect() {
  2. //獲取客戶端鏈接
  3. auto socket_temp = server->nextPendingConnection();//根據當前新鏈接建立一個QTepSocket
  4. m_socket=socket_temp;//記錄此鏈接用於後續數據讀寫
  5. //鏈接QTcpSocket的信號槽,以讀取新數據
  6. QObject::connect(socket_temp, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data);
  7. //當斷開鏈接時發出的信號
  8. QObject::connect(socket_temp, &QTcpSocket::disconnected, this, &MainWindow::socket_Disconnected);
  9. }

m_socket=socket_temp;//記錄此鏈接用於後續數據讀寫

這一行等因而每次有一個新的鏈接都替換了舊的鏈接記錄,天然之友最後一個客戶端鏈接有效,正確的能夠創建list存儲全部鏈接的socket,當收發數據時根據須要指定socket進行收發。這時將disconnected信號進行connect就具備了做用,當某個鏈接斷開時應該從全部鏈接鏈表中刪除此記錄。

由nextPendingConnection建立的QTcpSocket,會有QTcpServer維護,當QTcpServer銷燬是會自動銷燬全部建立的socket,若想提早釋放內容能夠在disconnected信號發生時主動delete

2.2. 關於QTcpServer

可能考慮到跨平臺問題,Qt使用select實現io多路複用,鏈接數量限制是1024,若須要poll,epoll等可以使用其餘庫,好比libevent

2.3. 關於數據收發

能夠經過setReadBufferSize設置接收緩衝區大小(Qt內部緩衝區大小)

當發送端發送的數據超過buffer大小時會觸發readyread信號,須要注意對此狀況的處理方法,能夠考慮在消息頭增長消息長度

未驗證:Qt有本身內部的緩衝區,消息發送到系統緩衝區,Qt會讀取出來,而調用的Qt函數readall等實際上讀取的是Qt內部緩衝區而非系統緩衝區

相關文章
相關標籤/搜索