Qt网络编程之TCP

1 QTcpServer类与QTcpSocket类

TCP(Transmission Control Protocol)是一种被大多数Internet网络协议(HTTP与FTP)用于数据传输的低级网络协议,它是可靠的、面向连接的、面向流的数据传输协议,特别适合连续数据的传输

  • QT中TCP通信过程!!!!!!!
    实现TCP通信必须要先建立TCP连接,通信端分为客户端和服务器端。

  • 连接的建立过程
    服务器端先用QTcpServer类的函数listen监听指定的地址和端口,指定具有该地址的客户端通过这一端口连接至服务器端。当客户端通过QTcpSocket类的connectToHost函数连接至服务器时,服务器信号newConnection被触发,服务器用函数nextPendingConnection获取该连接对应的套接字QTcpSocket,他们之间通过QTcpSocket类套接字进行通信。断开连接时客户端或服务器端通过QTcpSocket对象调用disconnectFromHost即可断开这个连接,另外客户端通过QTcpServer对象调用close可以停止监听过程。

  • 端口问题
    TCP中服务器调用listen监听指定地址,该地址的客户端才能连接服务器,listen指定的端口号是服务器的端口号,服务器在这一端口监听来自客户端的连接。客户端调用connectToHost连接指定的地址和端口,这都是用来指定服务器的参数。
    UDP中客户端调用bind绑定自己的某个端口,udp数据报通过这个端口进行传输,在writeDatagram发送数据报时指定了对方的端口号和地址。

  • 通信的实现过程
    对于基于行的数据通信,一般用于纯文本数据的通信,每行以换行符结束。先用canReadLine函数判断是否有一行数据可读,再用readLine函数读取并返回一行数据。用write函数发送数据。
    对于基于块的数据通信,用于一般的二进制数据的传输。先用bytesAvailable函数判断可读的数据字节数,然后用readAll读出可读的所有数据,或用read读出指定长度的数据。用write函数发送数据。

1.1 QTcpServer类

QTcpServer类的主要接口函数:

//公共函数
bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
bool QTcpServer::isListening() const;
[virtual] QTcpSocket *QTcpServer::nextPendingConnection();
int QTcpServer::maxPendingConnections() const;
void QTcpServer::close();
bool QTcpServer::waitForNewConnection(int msec = 0, bool *timedOut = Q_NULLPTR);
QHostAddress QTcpServer::serverAddress() const;
quint16 QTcpServer::serverPort() const
//信号
[signal] void QTcpServer::newConnection();
//保护成员,定义继承QTcpServer类的类时使用
[virtual protected] void QTcpServer::incomingConnection(qintptr socketDescriptor);
[protected] void QTcpServer::addPendingConnection(QTcpSocket *socket);

listen函数以非阻塞方式监听指定的端口和地址,address取值为QHostAddress::Any允许所有地址接入,port为0时允许所有端口接入。
isListening函数判断QTcpServer当前是否在监听。
信号newConnection当有客户端连接到来时被触发。
nextPendingConnection函数返回下一个等待接入的连接,返回的QTcpSocket对象用来与客户端进行通信。
maxPendingConnections函数返回服务器最大等待的连接数。
close函数关闭服务器端,不再监听。
waitForNewConnection函数将以阻塞方式等待新的连接,不推荐在GUI程序中使用。
incomingConnectionaddPendingConnection:当从QTcpServer中派生新类时才使用,此时用户要记得调用addPendingConnection,一般不需要用到。一般情况下,新连接可用时QTcpServer内部调用incomingConnection函数,创建一个QTcpSocket 对象,并调用addPendingConnection函数将其添加到内部可用新连接列表,然后发射newConnection信号。
serverAddress/serverPort函数当服务器处于监听状态时返回服务器地址和端口号。

1.2 QTcpSocket类

QTcpSocket类和QUdpSocket函数都从QAbstractSocket函数派生而来。
QAbstractSocket类的主要接口函数:

//公共函数
[virtual] void QAbstractSocket::connectToHost(const QHostAddress &address, quint16 port, OpenMode openMode = ReadWrite);
[virtual] void QAbstractSocket::disconnectFromHost();
[virtual] bool QAbstractSocket::waitForConnected(int msecs = 30000);
[virtual] bool QAbstractSocket::waitForDisconnected(int msecs = 30000);

QHostAddress QAbstractSocket::localAddress() const;
quint16 QAbstractSocket::localPort() const;
QHostAddress QAbstractSocket::peerAddress() const;
quint16 QAbstractSocket::peerPort() const;
QString QAbstractSocket::peerName() const;

SocketState QAbstractSocket::state() const;

[virtual] bool QAbstractSocket::canReadLine() const;
QByteArray QIODevice::readLine(qint64 maxSize = 0)
[virtual] qint64 QAbstractSocket::bytesAvailable() const;
QByteArray QIODevice::readAll();
QByteArray QIODevice::read(qint64 maxSize);
qint64 QIODevice::read(char *data, qint64 maxSize);
qint64 QIODevice::write(const char *data);
qint64 QIODevice::write(const char *data, qint64 maxSize);
//信号
[signal] void QAbstractSocket::connected();
[signal] void QAbstractSocket::disconnected();
[signal] void QAbstractSocket::stateChanged(QAbstractSocket::SocketState socketState);
[signal] void QIODevice::readyRead();

客户端用connectToHost函数以异步方式连接到指定IP地址和端口的服务器,连接成功后发射connected()信号。
disconnectFromHost函数断开socket,关闭成功后发射disconnected信号。
waitForConnectedwaitForDisconnected函数阻塞直到建立连接或断开连接。
localAddresslocalPort返回本socket的地址和端口号。
peerAddresspeerPortpeerName在连接建立状态下,返回对方地址、端口和主机名。
state函数返回socket的当前状态,状态变化时stateChanged信号被触发。

canReadLine函数当有一行数据可从socket缓冲区读取时,返回true。
readLine函数读取并返回一行数据。
bytesAvailable函数返回缓冲区可被读取的数据字节数。
readAll函数一次读取所有缓冲区的数据,返回类型为QByteArray。
readyRead信号当缓冲区有新数据可以读取时发射,我们可以在槽函数里读取缓冲区的数据。
write函数通过QTcpSocket发送数据

1.3 示例

//tcpServer.cpp
#include <QTcpServer>
QTcpSocket *tcpSocket;//用于和客户端通信的套接字
QTcpServer *tcpServer=new QTcpServer(this);
QString IP=ui->comboIP->currentText();
quint16 port=ui->spinPort->value();
QHostAddress addr(IP);
tcpServer->listen(addr,port);//开始监听
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));//连接到来时信号被触发

void MainWindow::onNewConnection()
{
    tcpSocket = tcpServer->nextPendingConnection(); //创建socket!!!!!!!!!!!

    connect(tcpSocket, SIGNAL(connected()),this, SLOT(onClientConnected()));
    connect(tcpSocket, SIGNAL(disconnected()),this, SLOT(onClientDisconnected()));
    connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
}
void MainWindow::onClientDisconnected()
{
    tcpSocket->deleteLater();
}
void MainWindow::onSocketReadyRead()
{//读取
	//读一行文本
    while(tcpSocket->canReadLine())
        ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readLine());
    //读一定的字节
    while(tcpSocket->bytesAvailable() > 0)
    {
        QByteArray ba = tcpSocket->readAll();
        QString in;
        in.append(ba);
        ui->plainTextEdit->appendPlainText("[in] "+ in);
    }
}
void MainWindow::on_btnSend_clicked()
{//发送
    QString  msg;
    QByteArray  str=msg.toUtf8();
    tcpSocket->write(str);
}

if (tcpServer->isListening()) //tcpServer正在监听
	tcpServer->close();//停止监听
//tcpClient.cpp
QTcpSocket  *tcpClient = new QTcpSocket(this);
QString addr=ui->comboServer->currentText();
quint16 port=ui->spinPort->value();
tcpClient->connectToHost(addr,port);//连接到服务器
connect(tcpClient,SIGNAL(connected()),this,SLOT(onConnected()));
connect(tcpClient,SIGNAL(disconnected()),this,SLOT(onDisconnected()));
connect(tcpClient,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
connect(tcpClient,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));

void MainWindow::onSocketReadyRead()
{//读取
    while(tcpClient->canReadLine())
        ui->plainTextEdit->appendPlainText("[in] "+tcpClient->readLine());
}

void MainWindow::on_btnSend_clicked()
{//发送
    QString  msg=ui->editMsg->text();
    ui->plainTextEdit->appendPlainText("[out] "+msg);
    QByteArray  str=msg.toUtf8();
 
    tcpClient->write(str);
}

//断开与服务器的连接
if (tcpClient->state()==QAbstractSocket::ConnectedState)
	tcpClient->disconnectFromHost();
  • 注意
    上面的代码TcpServer只允许一个客户端接入,而一般的TCP服务器允许多个客户端接入,我们应该为每个连接进来的socket创建一个线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值