Qt笔记:网络编程Tcp
一、铺垫
1.以下只是告诉诸位怎样去构建服务器与客户端;客户端这样构建肯定没问题;但是服务端不可能这样写,因为他是布置在Linux上的,纯数据类处理服务器,根本不可能用Qt写;这在Qt的http类中就表明了;
2.如果客户端不加密;和没穿衣服裸奔是一样的,加密我感觉才只是穿了条裤衩,最起码在奔跑的时候还有点遮挡,到了浴池都要脱(只要学过Linux网络编程,上网感觉就是在裸奔);所以这种方式只能存在于开源项目或者其他一些项目;Tcp的传输是按照字节流的粘包问题也需要程序员去搞定;问题还是蛮多的;
3.Qt不需要Linux的多线程来解决一次只能处理一个链接的问题,但是在多路转接上真实省了太多的脑细胞;而且可以设置定时器;来把超时的连接关掉;真是牛!!!
二、服务端
this->setWindowTitle("服务器");//1.修改窗口标题; QTcpServer* tcpServer=new QTcpServer(this);//2.创建实例 //3.信号和槽函数连接——当有新链接连上之时,会自动调用函数;connect(tcpServer,&QTcpServer::newConnection,this,&Widget::processConnection); //4.绑定并监听端口号 //这个操作是最后一步;//绑定并监听 if(!tcpServer->listen(QHostAddress::Any,9090)){ QMessageBox::information(this,"网络提示",tcpServer->errorString()+"绑定监听IP地址和端口号失败"); exit(1); } } void Widget::processConnection() { //1.通过tcpServer拿到一个socket对象,通过这个对象来和客户端进行通信 //当有连接进来之时,创建一个服务socket;linux来说是一个套接字; //peerAddress——对端地址;客户端地址; QTcpSocket* clientSocket = tcpServer->nextPendingConnection(); QString log = "["+clientSocket->peerAddress().toString()+":"+\ QString::number(clientSocket->peerPort())+"]客户端上线"; ui->listWidget->addItem(log); //2.通过信号槽来处理客户端发来的请求的情况——使用lamda表达式来写 connect(clientSocket,&QTcpSocket::readyRead,this,[=]() { //1)读取请求数据;此处readAll 返回的是QByteArray 通过赋值转成QString QString request = clientSocket->readAll(); //2) 根据请求处理响应——此处是回显;就不做处理; const QString& response =request; //3)把响应写回客户端 clientSocket->write(response.toUtf8()); //4)把上述信息记录到日志中 QString log = "["+clientSocket->peerAddress().toString()+":"+\ QString::number(clientSocket->peerPort())+"] req:"\ +request+"resp: "+response; ui->listWidget->addItem(log); }); //3.通过信号槽处理客户端断开连接的情况connect(clientSocket,&QTcpSocket::disconnected,this,[=](){ //1)把断开连接的信息通过日志显示出来 QString log = "["+clientSocket->peerAddress().toString()+":"+\ QString::number(clientSocket->peerPort())+"]客户端下线"; ui->listWidget->addItem(log); //2)手动释放clientSocket——随着服务器的运行,客户端越来越多,如果不是释放,此时累积的clientSocket也会越来越多文件描述符泄露,内存泄漏; //告诉QT,在下一轮事件循环中,再进行上述的销毁操作; clientSocket->deleteLater(); });}
三、客户端
//1.设置窗口标题 this->setWindowTitle("客户端"); //2.创建socket对象实例 socket = new QTcpSocket(this); //3.和服务器建立连接;调用这个函数,此时系统内核就会和对方的服务器进行三次握手; //此处这个函数不会阻塞等待三此握手完毕~(非阻塞函数); //原生linux API一般来说都是默认阻塞I/O通信的;此时必须要进行阻塞操作; socket->connectToHost("127.0.0.1",9090); //4.连接信号槽,去处理响应 connect(socket,&QTcpSocket::readyRead,this,[=](){ //读取出响应内容 QString response = socket->readAll(); ui->listWidget->addItem("服务器说:" + response); }); //5.等待连接建立的结果,确认是否连接成功 bool ret = socket->waitForConnected();//阻塞函数;判定是否建立连接成功 if(!ret){ QMessageBox::critical(this,"连接服务器出错",socket->errorString()); exit(1); } void Widget::on_pushButton_clicked() { //1.获取输入框中的内容 const QString& text=ui->lineEdit->text(); //2.发送数据给服务器 socket->write(text.toUtf8()); //3.把发的消息显示到界面上 ui->listWidget->addItem("客户端说:"+text); //4.清空输入框的内容 ui->lineEdit->setText(""); }