TCP通信,要区分服务端,和客户端。
服务端的功能是,设置要监听的端口,然后等待客户端发起的连接。
QT中TCP服务器端的编程步骤:
(1)new一个TCP服务器 QTcpServer
(2)进入listen监听状态(形参为:要监听的IP,一般填Any, 要监听的端口号)
(3)一旦有客户端申请接入,服务端会产生消息QTcpServer::newConnection,在消息的处理函数中,记录下客户端发起的socket连接QTcpSocket(一般要用链表数据结构记录,因为可能会有多个客户端要接入)。
(4)把刚才记录下的socket的【已连接】、【连接已断开】、【收到数据】3个常用的信号槽写好。(这一步骤和客户端编程是一样的,请参考我的另一篇博客《QT socket TCP通信程序模板- 客户端》)
(5)发送数据用QTcpSocket::write(uint8_t *bug, int65_t maxLen);
示例代码:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
#include <QMap>
#include <QByteArray>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_ptnCreateTcp_clicked();
void on_ptnSend_clicked();
void when_tcp_newConnection(void);
void when_tcpClientDisconnected(void);
void when_receivedData(void);
private:
Ui::MainWindow *ui;
QTcpServer *tcpServer;
QList<QTcpSocket*> tcpSktList;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#define debug_print(str) ui->textEditDebug->append(str)
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
tcpServer = new QTcpServer();
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(when_tcp_newConnection()));
for(int i = 0; i < ui->tableClients->rowCount(); i++)
{
ui->tableClients->setItem(i, 0, new QTableWidgetItem("无IP"));
ui->tableClients->setItem(i, 1, new QTableWidgetItem("无端口"));
ui->tableClients->setItem(i, 2, new QTableWidgetItem("未连接"));
}
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_ptnCreateTcp_clicked()//TCP服务器进入监听状态
{
uint16_t port = ui->spinPort->value();
tcpServer->close();//若listen时,想更换监听的端口号,必须先close掉
tcpServer->listen(QHostAddress::Any, port);
debug_print(QString("正在监听本机IP的第%1端口").arg(port));
}
void MainWindow::on_ptnSend_clicked()
{
}
void MainWindow::when_tcp_newConnection()
{
debug_print("有TCP客户端请求连接");
QTcpSocket *tcpSocket = tcpServer->nextPendingConnection();//新的客户端发起的连接
QHostAddress clientIp = tcpSocket->peerAddress();//客户端的IP
quint16 port = tcpSocket->peerPort();//客户端的端口
if(tcpSktList.contains(tcpSocket))
{
debug_print(QString("%1:%2的连接早已建立过").arg(clientIp.toString()).arg(port));
}
else
{
debug_print("新的连接已建立");
tcpSktList.append(tcpSocket);//记录下客户端发起的连接
connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(when_tcpClientDisconnected()));//客户端掉线处理
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(when_receivedData()));//客户端发来的数据处理
}
// ui->tableClients->item(0,0)->setText(clientIp.toString());//
// ui->tableClients->item(0,1)->setText(QString::number(port));
}
void MainWindow::when_tcpClientDisconnected(void)
{
debug_print("tcp客户端掉线");
QTcpSocket *tcpSocket = static_cast<QTcpSocket *>( QObject::sender() );
tcpSktList.removeOne(tcpSocket);
}
void MainWindow::when_receivedData()
{
QTcpSocket *tcpSocket = static_cast<QTcpSocket *>( QObject::sender() );
qDebug() <<QString("收到来自客户端%1的消息:").arg(tcpSocket->peerAddress().toString());
QByteArray ba = tcpSocket->readAll();
qDebug() << ba;//打印收到的来自客户端的消息
}
服务器端的TCP程序,不需要本机的IP地址,listen时,只填端口号即可。