Qt下的Tcp协议练习——客户端

上一篇文章记录了本次聊天室项目服务端的实现过程和主要代码,本篇文章将记录客户端的实现过程和主要代码。

至于Tcp的原理,上篇文章已经提到过了,所以在这里就不多啰嗦了。

还是一样的套路,上来先初始化控件对象和设置布局,这些都不是重点,可以自己随意布局。

    //设置窗口标题
    setWindowTitle(tr("TCP Client"));
    //初始化控件对象
    contentListWidget = new QListWidget;
    userNameLabel = new QLabel(tr("name:"));
    userNameLineEdit = new QLineEdit;
    serverIPLabel = new QLabel(tr("IP:"));
    serverIPLineEdit = new QLineEdit;
    portLabel = new QLabel(tr("port:"));
    portLineEdit = new QLineEdit;
    enterBtn = new QPushButton(tr("Enter the chat room!"));
    sendLineEdit = new QLineEdit;
    sendBtn = new QPushButton(tr("Send!"));
    mainLayout = new QGridLayout(this);
    //设置布局
    mainLayout->addWidget(userNameLabel,0,0);
    mainLayout->addWidget(userNameLineEdit,0,1);
    mainLayout->addWidget(serverIPLabel,1,0);
    mainLayout->addWidget(serverIPLineEdit,1,1);
    mainLayout->addWidget(portLabel,2,0);
    mainLayout->addWidget(portLineEdit,2,1);
    mainLayout->addWidget(enterBtn,3,0,1,2);
    mainLayout->addWidget(contentListWidget,4,0,1,2);
    mainLayout->addWidget(sendLineEdit,5,0);
    mainLayout->addWidget(sendBtn,5,1);

至于执行出来的效果呢,就是下面这个样子,有点丑陋,哈哈。

接下来就是一些关键函数的实现了,我会把一些说明写到代码的注释当中

    //记录当前状态,true表示已经进入聊天室,false表示不在聊天室中,根据status的值判断是进入还是离开聊天室
    status = false;
    //指定端口
    port = 80;
    //将端口显示到控件上
    portLineEdit->setText(QString::number(port));
    //初始化记录IP地址的对象
    serverIP = new QHostAddress();
    //将按钮的点击信号和想要对应的槽函数连接起来
    connect(enterBtn,SIGNAL(clicked(bool)),this,SLOT(slotEnter()));
    connect(sendBtn,SIGNAL(clicked(bool)),this,SLOT(slotSend()));
    //将发送信息按钮设置为不可点击状态
    sendBtn->setEnabled(false);

接下来实现两个槽函数

首先是加入enterBtn对应的加入聊天室的槽函数

这段代码有点长,主要还是按照当前是否已经连接到聊天室的两种情况分别进行处理

slotEnter():

    if(!status){//判断当前状态,是否已经加入到聊天室中
        //获取控件上输入的IP地址
        QString ip = serverIPLineEdit->text();

        if(!serverIP->setAddress(ip)){//判断获取的IP地址是否能够正常被解析
            //如果不能,则弹出警告
            QMessageBox::information(this,tr("error"),tr("ip error!"));
            return;
        }
        if(userNameLineEdit->text()==""){//判断控件中的用户名是否为空
            //如果用户名为空,则发出警告
            QMessageBox::information(this,tr("error"),tr("userName error!"));
            return;
        }
        //将控件中的用户名保存到之前定义的变量当中
        userName = userNameLineEdit->text();
        //初始化Tcp套接字,并各个信号和对应的槽函数连接起来
        tcpSocket = new QTcpSocket(this);
        connect(tcpSocket,SIGNAL(connected()),this,SLOT(slotConnected()));
        connect(tcpSocket,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));
        connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(dataReceived()));
        //与TCP服务端进行连接,成功的话会发送connected()信号
        tcpSocket->connectToHost(*serverIP,port);
        //记录当前连接状态,记录为已进入聊天室
        status = true;
    }else{//如果已经连接到了服务端,执行面下的操作
        //定义一个变量,用来保存信息的长度
        int length = 0;
        //定义一条离开聊天室的信息,离开聊天室时要发送这条信息给服务端
        QString msg = userName+tr(":Leave chat Room!");
        //通知服务端,我要离开聊天室了,也就是发送上面那条信息给服务端
        //如果发送成功,则会返回信息的长度,通过这种方式来判断,信息是否发送出去了
        if((length = tcpSocket->write(msg.toLatin1(),msg.length()))!=msg.length()){
            return;
        }
        //与服务端断开连接后,会发出disconnected()信号
        tcpSocket->disconnectFromHost();
        //保存当前状态,记录为已经离开聊天室
        status = false;
    }

当要连接服务端的时候发送connected()信号,触发slotConnected()槽函数,下面是槽函数的实现

slotConnected():

    //将发送信息按钮设置为可点击状态
    sendBtn->setEnabled(true);
    //将加入聊天室按钮的文字信息更改为leave
    enterBtn->setText(tr("Leave!"));
    //发送消息给服务端,通知服务端我要加入聊天室了,具体流程跟上面发送信息的流程相同,这里就不重复说明了
    int length = 0;
    QString msg = userName+tr(":Enter chat Room!");
    if((length = tcpSocket->write(msg.toLatin1(),msg.length()))!=msg.length()){
        return;
    }

当与服务端断开连接的时候发送disconnected()信号,触发slotDisconnected()槽函数,代码如下

slotDisconnected():

    //既然已经离开聊天室了,发送信息的按钮当然也就不能点啦
    sendBtn->setEnabled(false);
    //然后进入聊天室按钮的信息也要修改一下
    enterBtn->setText(tr("Enter the chat room!"));

当有数据到来时,就会触发dataReceived()槽函数,从套接字中取出有效数据并显示出来

dataReceived():

    //循环条件是等待读取的字节数大于0,也就是说还有数据没有读出来
    while(tcpSocket->bytesAvailable()>0){
        QByteArray datagram;
        //统一一下长度
        datagram.resize(tcpSocket->bytesAvailable());
        //开始读取有效数据
        tcpSocket->read(datagram.data(),datagram.size());
        //把读取到的数据转化为QString类型,方便显示
        QString msg = datagram.data();
        //把消息显示到控件上就ok了
        contentListWidget->addItem(msg.left(datagram.size()));
    }

最后要实现的是点击发送消息按钮时触发的槽函数slotSend()

slotSend():

    if(sendLineEdit->text()==""){//判断输入框中是否输入了消息
        return;
    }
    //把你的用户名拼接到消息前面,让其他用户知道是谁发送的消息
    QString msg = userName+":"+sendLineEdit->text();
    //开始向套接字中写入数据
    tcpSocket->write(msg.toLatin1(),msg.length());
    //最后,消息都发送出去了,肯定要把输入框里面的文字清空掉啦
    sendLineEdit->clear();

就这样,本次做的练习就结束了,这次练习主要是熟悉Tcp协议连接,断开连接,读取消息,发送消息的流程和实现方法。

这次练习之后会进行一段时间的吸收,后续可能会做一个融入更多自己理解的案例,如果有时间的话,哈哈,但是学习的步伐是不会停下来的,希望各位大佬能够多多指教,多多和我交流。

猜你喜欢

转载自blog.csdn.net/menger3388/article/details/85001395