1.TCP通信概述

tcp是一种用于数据传输的低级网络协议,它是可靠的、面向流、面向连接的传输协议,特别适合于连续数据传输。

服务器端使用QTcpServer用于端口监听,建立服务器;QTcpSocket用于建立连接后使用套接字进行通信。

2.常用API

void close() 关闭服务器,停止网络监听

bool listen() 在给定IP地址和端口上进行监听

QTcpSocket *nextPendingConnection() 返回下一个等待接入的连接

bool waitForNewConnection() 以阻塞方式等待新连接

3.示例

QT TCP服务器实现_服务器
服务器端程序首先使用listen()开始服务器监听,可以指定IP和端口,一般一个服务器程序只监听某个端口的网络连接。

当有新的客户端接入时,QTcpServer内部的incomingConnection()函数会创建一个与客户端连接的QTcpSocket对象,然后发射信号newConnection()。

所以在客户端与服务器建立TCP连接后,具体的数据通信是通过QTcpSocket完成的。

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
Q_OBJECT

public:
explicit Widget(QWidget *parent = 0);
~Widget();

private slots:

void on_btnStart_clicked();

void on_btnStop_clicked();

void on_btnClear_clicked();

void on_newConnection();

void onConnected();

void onDisConnected();

void onStateChanged(QAbstractSocket::SocketState socketState);

void onReadyRead();

void on_btnSend_clicked();

private:
Ui::Widget *ui;

QTcpServer *m_tcpServer = nullptr;
QTcpSocket *m_tcpSocket = nullptr;
};

#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include <QHostInfo>

Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);

//本地主机名
QString hostName = QHostInfo::localHostName();

//本机IP地址
QHostInfo hostInfo = QHostInfo::fromName(hostName);

//IP地址列表
QList<QHostAddress> addrList = hostInfo.addresses();
for(int i=0;i<addrList.count();i++)
{
QHostAddress host = addrList.at(i);

if(QAbstractSocket::IPv4Protocol == host.protocol())
{
QString ip = host.toString();
ui->comboBox->addItem(ip);
}
}

m_tcpServer = new QTcpServer(this);
connect(m_tcpServer,&QTcpServer::newConnection,this,&Widget::on_newConnection);
}

Widget::~Widget()
{
delete ui;
}

void Widget::on_btnStart_clicked()
{
//当前选择的ip
QString ip = ui->comboBox->currentText();

//端口
int port = ui->lineEditPort->text().toInt();

QHostAddress addr(ip);

//监听
m_tcpServer->listen(addr,port);

ui->plainTextEdit->appendPlainText("**开始监听...");

ui->plainTextEdit->appendPlainText("**服务器地址: "+m_tcpServer->serverAddress().toString());

ui->plainTextEdit->appendPlainText("**服务器端口: "+QString::number(m_tcpServer->serverPort()));

ui->btnStart->setEnabled(false);

ui->btnStop->setEnabled(true);

ui->lbListen->setText("正在监听");
}

void Widget::on_btnStop_clicked()
{
if(m_tcpServer->isListening())
{
m_tcpServer->close();
ui->btnStart->setEnabled(true);
ui->btnStop->setEnabled(false);
ui->lbListen->setText("停止监听");
ui->plainTextEdit->appendPlainText("**停止监听**");
}
}

void Widget::on_btnClear_clicked()
{
ui->plainTextEdit->clear();
}

void Widget::on_newConnection()
{
m_tcpSocket = m_tcpServer->nextPendingConnection();
connect(m_tcpSocket,&QTcpSocket::connected,this,&Widget::onConnected);
connect(m_tcpSocket,&QTcpSocket::disconnected,this,&Widget::onDisConnected);
connect(m_tcpSocket,&QTcpSocket::stateChanged,this,&Widget::onStateChanged);
connect(m_tcpSocket,&QTcpSocket::readyRead,this,&Widget::onReadyRead);

ui->plainTextEdit->appendPlainText("** client socket connected");
ui->plainTextEdit->appendPlainText("** peer address: "+m_tcpSocket->peerAddress().toString());
ui->plainTextEdit->appendPlainText("** peer port: "+QString::number(m_tcpSocket->peerPort()));
}

void Widget::onConnected()
{
ui->plainTextEdit->appendPlainText("** client socket connected");
ui->plainTextEdit->appendPlainText("** peer address: "+m_tcpSocket->peerAddress().toString());
ui->plainTextEdit->appendPlainText("** peer port: "+QString::number(m_tcpSocket->peerPort()));
}

void Widget::onDisConnected()
{
ui->plainTextEdit->appendPlainText("** client socket disconnected");
m_tcpSocket->deleteLater();
}

void Widget::onStateChanged(QAbstractSocket::SocketState socketState)
{
switch (socketState)
{
case QAbstractSocket::UnconnectedState:
ui->lbListen->setText("UnconnectedState");break;
case QAbstractSocket::HostLookupState:
ui->lbListen->setText("HostLookupState");break;
case QAbstractSocket::ConnectedState:
ui->lbListen->setText("ConnectedState");break;
case QAbstractSocket::ConnectingState:
ui->lbListen->setText("ConnectingState");break;
case QAbstractSocket::BoundState:
ui->lbListen->setText("BoundState");break;
case QAbstractSocket::ClosingState:
ui->lbListen->setText("ClosingState");break;
case QAbstractSocket::ListeningState:
ui->lbListen->setText("ListeningState");break;
}

}

void Widget::onReadyRead()
{
while(m_tcpSocket->canReadLine())
{
ui->plainTextEdit->appendPlainText("[in] "+m_tcpSocket->readLine());
}
}

void Widget::on_btnSend_clicked()
{
QString msg =ui->lineEdit->text();
ui->plainTextEdit->appendPlainText("[out]"+msg);
QByteArray str = msg.toUtf8();
str.append('\n');
m_tcpSocket->write(str);
}

一般TCP服务器程序允许多个客户端接入,本例只演示了一个客户端接入,为了使每个socket连接通信互不影响,一般采用多线程,即为一个socket连接创建一个线程。

4.与客户端通信

QT TCP服务器实现_#include_02