Qt下的Tcp协议练习——服务端

1.Tcp协议的原理

Tcp协议是一种可靠、面向连接、面向数据流的传输协议,适合数据的连续传输。

Tcp协议能够确保一台计算机发出的数据无差错的传输给网络上的其他计算机,但是在传输数据前,必须建立连接(三次握手)。

2.传输过程

首先,服务端和客户端通过三次握手建立连接。

然后,客户端向服务端发送一个请求,服务端处理这个请求,并向客户端返回一个响应,这个过程会一直持续。

直到客户端为服务端发送一个文件结束符,并关闭客户端连接。

最后,服务端也关闭连接,结束运行。

3.实例

一个基于Tcp协议的聊天室Demo

创建TcpServer类,在构造函数中定义各个控件并完成初始化和布局

    //初始化对象
    ContentListWidget = new QListWidget;
    PortLabel = new QLabel(tr("Port:"));
    PortLineEdit = new QLineEdit;
    CreateBtn = new QPushButton(tr("Create talkRoom"));
    mainLayout = new QGridLayout(this);

    //控件布局
    mainLayout->addWidget(PortLabel,0,0);
    mainLayout->addWidget(PortLineEdit,0,1);
    mainLayout->addWidget(ContentListWidget,1,0,1,2);
    mainLayout->addWidget(CreateBtn,2,0,1,2);

画面效果

创建TcpClientSocket类,用来接收各个客户端发送的数据,在构造函数中完成以下代码

扫描二维码关注公众号,回复: 4581564 查看本文章
    //在Qt中,QIODevice是所有I/O设备的一个抽象类,QTcpSocket也被当做一个QIODevice
    //当接收到数据报的时候,发出信号readyRead()
    connect(this,SIGNAL(readyRead()),this,SLOT(dataReceived()));

    //在连接断开的时候,发出信号disconnected()
    connect(this,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));

下面是上述两个槽函数的实现

dataReceived():

   while(bytesAvailable()>0){//判断等待读取的传入字节数是否大于0
                              //(也就是判断是否有没读取的有效数据)

        //保存有效数据的长度
        int lenght = bytesAvailable();
        char buf[1024];

        //写入到buf中,并转换成QString类型
        read(buf,lenght);
        QString msg = buf;

        //发送信号,向客户端广播消息
        emit updateClients(msg,lenght);
    }

slotDisconnected(): 

    //socketDescriptor()的返回值是socket的描述符,如果没有连接则返回-1
    emit disconnected(this->socketDescriptor());

创建Server类,用来监听指定端口的Tcp连接,在构造函数中完成以下代码

    //QHostAddress定义的技术特殊IP地址
    //Null:空地址
    //LocalHost:IPv4的本机地址
    //LocalHostIPv6:IPv6的本机地址
    //Broadcast:广播地址
    //Any:IPv4的任意地址
    //AnyIPv6:IPv6的任意地址
    //监听指定IP地址
    listen(QHostAddress::Any,port);

实现下面三个函数

重载 incomingConnection(qintptr socketDescriptor):

这里格外注意:因为QT5.0版本之前incomingConnection函数的参数类型是int,但是5.0以后变成了qintptr,如果这儿写错了,即使是有新连接加入也不会触发incomingConnection​​​​​​​函数。

    //创建一个新的TcpClientSocket与客户端通信
    TcpClientSocket *tcpClientSocket = new TcpClientSocket(this);

    //连接TcpClientSOcket的信号
    connect(tcpClientSocket,SIGNAL(updateClients(QString,int)),this,SLOT(updateClients(QString,int)));
    connect(tcpClientSocket,SIGNAL(disconnected(int)),this,SLOT(slotDisconnected(int)));

    //将新创建的套接字的描述符指定为传入的socketDescriptor
    tcpClientSocket->setSocketDescriptor(socketDescriptor);

    //将套接字加入套接字列表
    tcpClientSocketList.append(tcpClientSocket);

updateClients(QString msg, int length): 

    //发送信号,更新服务端窗口信息
    emit updateServer(msg,length);

    //向套接字列表中的每一项发送广播
    for(int i = 0;i<tcpClientSocketList.count();i++){
        QTcpSocket *item = tcpClientSocketList.at(i);
        if(item->write(msg.toLatin1(),length)!=length){
            continue;
        }
    }

slotDisconnected(int descriptor): 

    for(int i = 0;i<tcpClientSocketList.count();i++){
        QTcpSocket *item = tcpClientSocketList.at(i);
        if(item->socketDescriptor()==descriptor){
            //从列表中删除传入的标识符所代表的套接字(这个函数的作用是删除列表中已断开连接的套接字)
            tcpClientSocketList.removeAt(i);
            return;
        }
    }
    return;

在TcpServer类中写入下列代码,

    //设置端口号
    port = 80;
    //将端口号显示到控件上
    PortLineEdit->setText(QString::number(port));
    //点击按钮创建服务
    connect(CreateBtn,SIGNAL(clicked(bool)),this,SLOT(slotCreateServer()));

实现下面的槽函数。

slotCreateServer():

    //创建一个Server对象
    server = new Server(this,port);
    //将Server类中的信号和TcpServer中的槽函数连接起来
    connect(server,SIGNAL(updateServer(QString,int)),this,SLOT(updateServer(QString,int)));
    //将按钮设置为不可点击状态
    CreateBtn->setEnabled(false);

 updateServer(QString msg, int length):

//将信息显示到控件上
ContentListWidget->addItem(msg.left(length));

强调一个重点,因为项目中使用了网络相关的功能,所以要在工程文件中添加下面的代码

QT       += network

以上就是这个简略的服务端的实现和主要代码,因为目前还是处在一个模仿和学习的阶段,所以主要还是借鉴一些书上的案例和网上的Demo,后续会根据自己的掌握程度做一些更加能够体现自身理解的练习项目。

猜你喜欢

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