概念:tcp是面向连接,传输可靠,用于传输大量数据,速度比较慢,建立连接需要的开销比较多

套接字类:QTcpSocket

//常用函数
abort(); //如果客户端与服务器已经连接,断开服务器,通常用在连接服务器前
connectToHost(); //连接服务器。参数:1.网络地址 2.端口号
disconnectFromHost(); //关闭连接
write(); //向外界发送数据。参数:发送的内容(const char*或QByteArray型)
readAll(); //读取外界传入的所有数据,返回值:QByteArray型
waitForConnected(); //等待与外界连接。参数:等待时间(毫秒单位),默认为3秒
waitForBytesWritten(); //写入多久,才执行后面的语句。参数:写入时间(毫秒单位),默认为3秒
waitForReadyRead(); //读取多久,才执行后面的语句。参数:读取时间(毫秒单位),默认为3秒

errorString(); //返回错误信息
isValid(); //判断套接字是否有效
isOpen(); //判断套接字是否打开
flush(); //刷新数据区
close(); //关闭套接字

//信号函数
connected(); //连接成功相应
disconnected(); //断开连接后相应
readyRead(); //有外界数据传入时相应
bytesWritten(qint64); //向外界发送数据成功后相应,参数为发送的字节数

服务器使用到的服务类:QTcpServer

//函数
isListening(); //判断是否处于监听状态
listen(); //监听。参数:1.服务端网络地址 2.服务端端口号
nextPendingConnection(); //外界有客户端连接后,得到套接字对象
close(); //关闭服务

//信号函数
newConnection(); //外界有客户端连接后响应

数据的传输以QByteArray类型的形式发送,介绍QString与QByteArray类型的转换

  • QByteArray转QString:1.QString强转  2.QString静态方法fromLocal8Bit
  • QString转QByteArray:1.QString函数:toUtf8();  2.QString函数:toLocal8Bit()

一、客户端:Client

1.客户端与服务端的进行通信的主要步骤

  • 通过服务器的网络地址(ip)和端口号与服务器连接(前提:服务器处于开启状态)
  • 与服务器连接成功后,进行数据的传输与接收
  • 关闭客户端

2.下列演示一个客户端

QT学习day12---网络编程之TCP

//客户端类
class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
private:
    Ui::Widget *ui;
    QTcpSocket* clientSocket;
    bool isConnect;//一个标志,用于判断是否连接服务器
private slots:
    void connectServerSlot();
    void isConnectSlot();
    void isDisConnectSlot();
    void recvDataFromServerSlot();
    void sendDataToServerSlot();
};
Widget::Widget(QWidget *parent) :
    QWidget(parent),isConnect(false),//初始化连接表示为false
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    clientSocket=new QTcpSocket(this);
    connect(ui->conServerBtn,SIGNAL(clicked()),this,SLOT(connectServerSlot()));//点击按钮连接/断开服务器
    connect(clientSocket,SIGNAL(connected()),this,SLOT(isConnectSlot()));//连接成功后相应
    connect(clientSocket,SIGNAL(disconnected()),this,SLOT(isDisConnectSlot()));//如果没有连接相应
    connect(ui->sendMsgBtn,SIGNAL(clicked()),this,SLOT(sendDataToServerSlot()));//点击按钮发送消息
}

Widget::~Widget()
{
    if(clientSocket->isOpen())
        clientSocket->close();//关闭套接字
    delete clientSocket;//释放套接字
    delete ui;
}

void Widget::connectServerSlot()
{
    if(!isConnect)//如果当前未连接
    {
        QString ServerIp=ui->serverIpLEdit->text();//得到服务器IP
        QString Port=ui->portLEdit->text();//得到服务器端口号
        clientSocket->connectToHost(QHostAddress(ServerIp),Port.toInt());//通过IP与端口号连接服务器
        if(clientSocket->waitForConnected(1000))//如果等待一秒内连接成功
        {
            QMessageBox::information(this,QStringLiteral("提示"),QStringLiteral("连接服务器成功"));
            isConnect=true;
        }
        else//如果连接超时
        {
            clientSocket->disconnect();//套接字不连接
            QMessageBox::warning(this,QStringLiteral("提示"),QStringLiteral("连接服务器失败"));
        }
    }
    else//如果当前连接
    {
        clientSocket->close();//关闭套接字
        QMessageBox::information(this,QStringLiteral("提示"),QStringLiteral("断开服务器成功"));
        isConnect=false;
    }
}

void Widget::isDisConnectSlot()
{
    ui->conServerBtn->setText(QStringLiteral("连接服务器"));
}

void Widget::isConnectSlot()
{
    ui->conServerBtn->setText(QStringLiteral("断开服务器"));
    //连接成功后,查看是否有数据发送过来
    connect(clientSocket,SIGNAL(readyRead()),this,SLOT(recvDataFromServerSlot()));
}

void Widget::recvDataFromServerSlot()//接受数据
{
    QByteArray recvData=clientSocket->readAll();//以字节类型得到数据
    ui->recvTBrowser->append(QStringLiteral("服务器:")+QString::fromLocal8Bit(recvData));
    ui->recvSizeTBrowser->setText(QString::number(recvData.size()));
}

void Widget::sendDataToServerSlot()//发送数据出去
{
    QString sendData=ui->sendTEdit->toPlainText();
    if(clientSocket->isOpen())//如果套接字处于打开状态
    {
        clientSocket->write(sendData.toLocal8Bit());//写数据
        ui->recvTBrowser->append(QStringLiteral("客户端:")+sendData);
        ui->sendSizeTBrowser->setText(QString::number(sendData.toLocal8Bit().size()));
        ui->sendTEdit->clear();
    }
}

 

二、服务器:Server

服务器与客户端的不同:服务器需要提供一个服务类,并用此类进行对外界的监听

1.客户端与服务端的进行通信的主要步骤

  • 服务器开启服务,开启监听,监听外界是否有客户端连接
  • 有客户端连接成功后,与客户端进行数据的传输
  • 不需要时,关闭服务

2.下列演示一个服务端

QT学习day12---网络编程之TCP

//服务端类
class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
private:
    Ui::Widget *ui;
    QTcpServer* tcpServer;//服务
    QTcpSocket* tcpServerSocket;//套接字
private:
    void showHostAddress();
private slots:
    void listenSlot();
    void newConSlot();
    void recvDataFromClientSlot();
    void sendDataToClientSlot();
};
Widget::Widget(QWidget *parent) :
    QWidget(parent),ui(new Ui::Widget)
{
    ui->setupUi(this);

    showHostAddress();//打印主机网络地址和端口
    tcpServer=new QTcpServer(this);

    connect(ui->listenBtn,SIGNAL(clicked()),this,SLOT(listenSlot())); //点击按钮开启加监听
    connect(tcpServer,SIGNAL(newConnection()),this,SLOT(newConSlot()));//如果外界有客户端连接
    connect(ui->sendMsgBtn,SIGNAL(clicked()),this,SLOT(sendDataToClientSlot()));//点击按钮发送数据
}

void Widget::showHostAddress()
{
    //allAddresses:得到所有网络地址
    QList<QHostAddress> addressList=QNetworkInterface::allAddresses();
    foreach(QHostAddress address,addressList)//遍历网络地址
    {
        if(address.isNull())//为空退出
            continue;
        QAbstractSocket::NetworkLayerProtocol protocol=address.protocol();//得到网络地址类型
        if(protocol!=QAbstractSocket::IPv4Protocol)//此处设置为判断是否为IPV4网络地址
            continue;
        ui->ipComBox->addItem(address.toString());//如果是IPV4,添加进组合框
    }
}

void Widget::listenSlot()//监听
{
    if(!tcpServer->isListening())//如果不处于监听状态,开启监听
    {
        //如果监听成功,参数:1.服务器IP地址 2.服务器端口号
        if(tcpServer->listen(QHostAddress(ui->ipComBox->currentText()),\
                          ui->portLEdit->text().toInt()))
        {
            QMessageBox::information(this,QStringLiteral("提示"),QStringLiteral("启动监听成功"));
            ui->listenBtn->setText(QStringLiteral("关闭监听"));
        }
        else
        {
            QMessageBox::warning(this,QStringLiteral("提示"),QStringLiteral("启动监听失败"));
        }
    }
    else//如果处于监听状态,关闭监听
    {
        tcpServer->close();//关闭服务
        tcpServerSocket->close();//关闭套接字
        ui->clientTBrowser->clear();
        ui->recvTBrowser->clear();
        ui->recvSizeTBrowser->clear();
        ui->sendSizeTBrowser->clear();
        ui->listenBtn->setText(QStringLiteral("开启监听"));
    }
}

void Widget::newConSlot()
{
    tcpServerSocket=tcpServer->nextPendingConnection();//得到传入的客户套接字
    QString clientName=tcpServerSocket->peerName();//得到客户端的名称
    QHostAddress clientAddress=tcpServerSocket->peerAddress();//得到客户端的网络地址
    qint64 clientPort=tcpServerSocket->peerPort();//得到客户端的端口

    ui->clientTBrowser->append(QStringLiteral("客户端名:")+clientName+"\n");
    ui->clientTBrowser->append(QStringLiteral("客户端IP:")+clientAddress.toString()+"\n");
    ui->clientTBrowser->append(QStringLiteral("客户端端口:")+QString::number(clientPort)+"\n");
    connect(tcpServerSocket,SIGNAL(readyRead()),this,SLOT(recvDataFromClientSlot()));//等待外界数据传入
}

void Widget::recvDataFromClientSlot()
{
    QByteArray recvData=tcpServerSocket->readAll();//读取所有数据
    ui->recvTBrowser->append(QStringLiteral("客户端:")+QString::fromLocal8Bit(recvData));
    ui->recvSizeTBrowser->setText(QString::number(recvData.size()));
}

void Widget::sendDataToClientSlot()
{
    QString sendData=ui->sendTEdit->toPlainText();
    tcpServerSocket->write(sendData.toLocal8Bit());//向外发送数据
    ui->recvTBrowser->append(QStringLiteral("服务端:")+sendData);
    ui->sendSizeTBrowser->setText(QString::number(sendData.toLocal8Bit().size()));
    ui->sendTEdit->clear();
}

三、运行结果

QT学习day12---网络编程之TCP

 

四、三次握手

服务端和客户端建立稳定的传输通道,需要3个步骤

  1. 客户端向服务器发送信息,发送一个报文(syn(请求同步))
  2. 服务端将受到的客户端的报文重新发回去,再多加一个报文(ack(确认))
  3. 客户端再向服务端发送报文(ack)

五、四次挥手

服务端和客户端断开传输通断,需要4个步骤

  1. 客户端向服务端发送报文(fin(结束标志))
  2. 服务端收到这个报文,它回复一个报文(ack)
  3. 服务端关闭客户端连接
  4. 客户端发挥(ack)报文确认

 

相关文章:

  • 2021-12-14
  • 2022-12-23
  • 2021-08-07
  • 2021-06-13
  • 2022-12-23
  • 2021-11-30
猜你喜欢
  • 2021-12-13
  • 2021-06-07
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-12-30
相关资源
相似解决方案