范文健康探索娱乐情感热点
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Qt开发TCPIP网络通信

  TCP/IP通信(即SOCKET通信)是通过网线将 服务器Server端  和 客户机Client端  进行连接,在遵循ISO/OSI模型的四层层级构架的基础上通过TCP/IP协议建立的通讯。控制器可以设置为服务器端或客户端。
  关于TCP/IP协议可详看:TCP/IP协议详解 - 知乎 (zhihu.com)
  总的来说,TCP/IP通讯有两个部分: 客户端 和 服务器 QTcpServer(监听套接字) 和 QTcpSocket(通讯套接字)
  监听套接字,顾名思义,监听关于各种通讯的状态,一旦进行通讯,监听套接字会启动通讯套接字,进行通讯
  客户端使用connectToHost函数主动连接服务器后,服务器会触发newConnectio这个槽函数,并进行取出QTcpServer(监听套接字),将相关内容取出并赋给QTcpSocket(通讯套接字)。
  客户端向服务器发送数据,触发readyRead(),进行处理,彼此传递时,原理都是这样的。
  对双方来说都起作用的部分: 一旦建立连接,就会触发connected,服务器特殊一点,触发的是newConnectio 互传数据也是一样的,一旦接受到,就会触发readyread
  服务器中,需要监听套接字以及通讯套接字,监听套接字用于监听客户端是否给服务器发送请求
  本篇博文做了初步的学习与尝试,编写了一个客户端和服务器基于窗口通信以及文件传输的小例程。 一,客户端
  客户端的代码比服务器稍简单,总的来说,使用QT中的 QTcpSocket类  与服务器进行通信只需要以下5步:
  (1)创建QTcpSocket套接字对象     socket = new QTcpSocket(this);
  (2)使用这个对象连接服务器     QString ip = ui.lineEdit_ip->text();//获取ip     int port = ui.lineEdit_2->text().toInt();//获取端口数据     socket->connectToHost(ip, port);
  (3)使用write函数向服务器发送数据     QByteArray data = ui.lineEdit_3->text().toUtf8();//获取lineEdit控件中的数据并发送给服务器     socket->write(data);
  (4)当socket接收缓冲区有新数据到来时,会发出readRead()信号,因此为该信号添加槽函数以读取数据  connect(socket, &QTcpSocket::readyRead, this, &QTcpClinet::ReadData); void QTcpClinet::ReadData() {     QByteArray buf = socket->readAll();     ui.textEdit->append(buf); }
  (5)断开与服务器的连接(关于close()和disconnectFromHost()的区别,可以按F1看帮助) socket->disconnectFromHost();
  客户端例程:(新建一个qt项目QTcpClinet(客户机))  ui界面
  本地回路ip:127.0.0.1 可以连接到本地ip(电脑内部循环的ip)
  如果要和局域网其他ip连接 -> 在运行(win+R)+cmd+ipconfig ->ipv4地址 查看本机ip
  点击领取Qt学习资料+视频教程~「链接」
  QTcpClinet.h #include  #include "ui_QTcpClinet.h" #include"QTcpSocket.h" #pragma execution_character_set("utf-8") class QTcpClinet : public QWidget {     Q_OBJECT  public:     QTcpClinet(QWidget *parent = Q_NULLPTR);     ~QTcpClinet(); public slots:     void on_btn_connect_clicked();     void ReadData();     void on_btn_push_clicked(); private:     Ui::QTcpClinetClass ui;     QTcpSocket* socket;//创建socket指针 };QTcpClinet.cpp #include "QTcpClinet.h"  QTcpClinet::QTcpClinet(QWidget *parent)     : QWidget(parent) {     ui.setupUi(this);     socket = new QTcpSocket(this); }  QTcpClinet::~QTcpClinet() {     delete this->socket;//回收内存 }  void QTcpClinet::on_btn_connect_clicked() {   if (ui.btn_connect->text()==tr("连接服务器"))   {     QString ip = ui.lineEdit_ip->text();//获取ip     int port = ui.lineEdit_2->text().toInt();//获取端口数据     //取消已有的连接     socket->abort();     //连接服务器     socket->connectToHost(ip, port);     bool isconnect = socket->waitForConnected();//等待直到连接成功     //如果连接成功     if (isconnect)     {         ui.textEdit->append("The connection was successful!!");         ui.btn_push->setEnabled(true);//按钮使能         //修改按键文字         ui.btn_connect->setText("断开服务器连接");         //接收缓冲区(服务器)信息         connect(socket, &QTcpSocket::readyRead, this, &QTcpClinet::ReadData);     }     else     {         ui.textEdit->append("The connection falied!!");     }   }   else   {       //断开连接       socket->disconnectFromHost();       ui.btn_connect->setText("连接服务器");       ui.btn_push->setEnabled(false);//关闭发送按钮使能   }  }  //接收缓冲区信息函数 void QTcpClinet::ReadData() {     QByteArray buf = socket->readAll();     ui.textEdit->append(buf); } //发送按钮事件 void QTcpClinet::on_btn_push_clicked() {     QByteArray data = ui.lineEdit_3->text().toUtf8();//获取lineEdit控件中的数据并发送给服务器     socket->write(data);     //判断是否写入成功     bool iswrite = socket->waitForBytesWritten();     if (iswrite)     {         //写入成功     }     else     {         //没有写入成功     } }二,服务器(需要一直运行哦)
  服务器除了使用到了 QTcpSocket类  ,还需要用到 QTcpSever类  。即便如此,也只是比客户端复杂一点点,用到了6个步骤:
  (1)创建QTcpSever对象     server = new QTcpServer(this);
  (2)侦听一个端口,使得客户端可以使用这个端口访问服务器     server->listen(QHostAddress::Any, 6677);//监听所有ip和6677端口
  (3)当服务器被客户端访问时,会发出newConnection()信号,因此为该信号添加槽函数,并用一个QTcpSocket对象接受客户端访问 connect(server, &QTcpServer::newConnection, this, &TcpServer::ClientConnect); void TcpServer::ClientConnect() {     //解析所有客户连接     while (server->hasPendingConnections())     {         //连接上后通过socket(QTcpSocket对象)获取连接信息         socket = server->nextPendingConnection();         QString str = QString("[ip:%1,port:%2]").arg(socket->peerAddress().toString()).arg(socket->peerPort());//监听客户端是否有消息发送         connect(socket, &QTcpSocket::readyRead, this, &TcpServer::ReadData1);     } }
  (4)使用socket的write函数向客户端发送数据 socket->write(data);
  (5)当socket接收缓冲区有新数据到来时,会发出readRead()信号,因此为该信号添加槽函数以读取数据 //监听客户端是否有消息发送 connect(socket, &QTcpSocket::readyRead, this, &TcpServer::ReadData1); //获取客户端向服务器发送的信息 void TcpServer::ReadData1() {     QByteArray buf = socket->readAll();//readAll最多接收65532的数据     QString str = QString("[ip:%1,port:%2]").arg(socket->peerAddress().toString()).arg(socket->peerPort());     ui.textEdit_server->append(str +QString(buf));     //socket->write("ok");//服务器接收到信息后返回一个ok }
  (6)取消侦听 server->close();
  服务器例程:(添加一个新的qt项目TcpServer(服务器))  ui界面 TcpServer.h #include  #include"ui_TcpServer.h" #include"qtcpserver.h" #include"qtcpsocket.h"  class TcpServer : public QWidget {     Q_OBJECT  public:     TcpServer(QWidget *parent = Q_NULLPTR);     ~TcpServer(); public slots:     void on_btn_server_clicked();     void on_btn_listen_clicked(); private:     Ui::TcpServerClass ui;     QTcpServer* server;     QTcpSocket* socket;//一个客户端对应一个socket     void ClientConnect();     void ReadData1();      };TcpServer.cpp #include "TcpServer.h" #include"qstring.h" #include"qdebug.h" #pragma execution_character_set("utf-8") TcpServer::TcpServer(QWidget *parent)     : QWidget(parent) {     ui.setupUi(this);     server = new QTcpServer(this);    //客户机连接信号槽     connect(server, &QTcpServer::newConnection, this, &TcpServer::ClientConnect); }  TcpServer::~TcpServer() {     server->close();     server->deleteLater(); }  void TcpServer::on_btn_listen_clicked() {     if (ui.btn_listen->text()=="侦听")     {         //从输入框获取端口号         int port = ui.lineEdit_port->text().toInt();         //侦听指定端口的所有ip         if (!server->listen(QHostAddress::Any, port))         {             //若出错,则输出错误信息             qDebug() << server->errorString();             return;         }         //修改按键文字         ui.btn_listen->setText("取消侦听");         }     else     {         socket->abort();         //取消侦听         server->close();         //修改按键文字         ui.btn_listen->setText("侦听");     } }  void TcpServer::ClientConnect() {     //解析所有客户连接     while (server->hasPendingConnections())     {         //连接上后通过socket获取连接信息         socket = server->nextPendingConnection();         QString str = QString("[ip:%1,port:%2]").arg(socket->peerAddress().toString()).arg(socket->peerPort());         //提示连接成功         ui.textEdit_server->append(str+"Connect to the server");         //复选框选项为连接服务器的ip         ui.comboBox->addItem(str);         //将socket地址放入combobox属性内         //ui.comboBox->setItemData(ui.comboBox->count()-1, QVariant((int)socket));         //监听客户端是否有消息发送         connect(socket, &QTcpSocket::readyRead, this, &TcpServer::ReadData1);     } }  //获取客户端向服务器发送的信息 void TcpServer::ReadData1() {     QByteArray buf = socket->readAll();//readAll最多接收65532的数据     QString str = QString("[ip:%1,port:%2]").arg(socket->peerAddress().toString()).arg(socket->peerPort());     ui.textEdit_server->append(str +QString(buf)); }  //服务器向客户端发送信息 void TcpServer::on_btn_server_clicked() {   if(ui.comboBox->count()== 0)return;   //QTcpSocket* skt=  (QTcpSocket*)ui.comboBox->itemData(ui.comboBox->currentIndex()).value();   socket->write(ui.lineEdit1->text().toUtf8()); }
  注意 :write中需要写入char类型的元素或QByteArray类型的元素
  效果展示:
  三,TCP/IP文件传输
  上文实现了消息的传输,由于 socket->readAll();(readAll最多接收65532的数据)  ,因此对于大文件的传输用此方法是不可取的。
  点击领取Qt学习资料+视频教程~「链接」
  TCP/IP文件传输的思路: 客户端和服务器连接 客户端选择文件,并发送文件给服务器(发送的是文件的帧头,格式:文件名&大小) 服务器触发readyRead,然后解析文件帧头(获取文件名和大小),并返回客户端一个ok消息 客户端触发readyRead,然后发送文件数据,通过progressBar显示进度 服务器再次触发readyRead,接收文件数据,并保存(通过ishead判断接收的是文件帧头还是文件数据)
  代码实现:
  新建服务器项目(TcpServer) TcpServer.h #pragma once  #include  #include "ui_TcpServer.h" #include"qtcpserver.h" #include"qtcpsocket.h" #pragma execution_character_set("utf-8") class TcpServer : public QWidget {     Q_OBJECT  public:     TcpServer(QWidget *parent = Q_NULLPTR);     void hasConnect(); private:     Ui::TcpServerClass ui;     QTcpServer* server;     QTcpSocket* socket;     bool ishead;     QString fileName;     int fileSize;//接收文件的总大小     int recvSize;//当前接收文件的大小     QByteArray filebuf;//当前接收的文件数据 };TcpServer.cpp #include "TcpServer.h" #include"qfile.h" TcpServer::TcpServer(QWidget *parent)     : QWidget(parent) {     ishead = true;     ui.setupUi(this);     server = new QTcpServer(this);     //监听1122端口的ip     server->listen(QHostAddress::Any, 1122);     //如果有用户连接触发槽函数     connect(server, &QTcpServer::newConnection, this, &TcpServer::hasConnect); }  void TcpServer::hasConnect() {     while (server->hasPendingConnections()>0)//判断当前连接了多少人     {         //用socket和我们的客户端连接,一个客户端对应一个套接字socket         socket = server->nextPendingConnection();         //服务器界面上输出客户端信息         ui.textEdit->append(QString("%1:新用户连接").arg(socket->peerPort()));         //如果客户端发送信息过来了,触发匿名函数         connect(socket, &QTcpSocket::readyRead, [=]() {             QByteArray buf = socket->readAll();             //用一个标志位ishead判断是头还是数据位             if (ishead)             {                 //如果是头,解析头(文件名,文件大小)                 QString str = QString(buf);                 ui.textEdit->append(str);                 QStringList strlist = str.split("&");                 fileName = strlist.at(0);//解析帧头文件名                 fileSize = strlist.at(1).toInt();//解析帧头文件大小                 ishead = false;//下次接收到的文件就是我们的数据                 recvSize = 0;                 filebuf.clear();                 socket->write("ok");             }             else             {                 //根据文件名和文件大小接收和保存文件                 filebuf.append(buf);                 recvSize += buf.size();//每接收一次文件,当前文件大小+1                 //当接收文件大小等于总文件大小,即文件数据接收完毕                 if (recvSize>=fileSize)                 {                     //保存文件                     QFile file(ui.lineEdit->text() + fileName);                     file.open(QIODevice::WriteOnly);                     file.write(filebuf);                     file.close();                     ishead = true;                 }             }             });     } }
  新建客户端项目(QTcpClient) QTcpClient.h #include  #include"ui_QTcpClient.h" #include"qtcpsocket.h" #pragma execution_character_set("utf-8") class QTcpClient : public QWidget {     Q_OBJECT  public:     QTcpClient(QWidget *parent = Q_NULLPTR); public slots:     void on_btn_connect_clicked();     void on_btn_choose_clicked();     void on_btn_open_clicked();      private:     Ui::QTcpClientClass ui;     QTcpSocket* socket; };QTcpClient.cpp #include "QTcpClient.h" #include"qfiledialog.h" #include"qfileinfo.h" QTcpClient::QTcpClient(QWidget *parent)     : QWidget(parent) {     ui.setupUi(this);     socket = new QTcpSocket(this);      } void QTcpClient::on_btn_connect_clicked() {     QString ip = ui.lineEdit_ip->text();//获取ip     int port = ui.lineEdit_port->text().toInt();//获取端口数据     socket->connectToHost(ip, port);//连接服务器     //等待连接成功     if (socket->waitForConnected())     {         ui.textEdit->append("连接服务器成功!");             ui.btn_open->setEnabled(true);                  //如果服务器发送信息到客户端,触发匿名函数         connect(socket, &QTcpSocket::readyRead, [=]() {             //读取服务器发送的信息(即缓冲区信息)             QByteArray buf = socket->readAll();             if (buf=="ok")             {                 QFile file = (ui.label_path->text());                 if (!file.open(QIODevice::ReadWrite))                 {                     //读取文件失败                     return;                 }                 qint64 currentlen = 0;//当前已经发送的大小                 qint64 allLength = file.size();//总文件大小                 do                 {                     char data[1024];                     qint64 msize = file.read(data, 1024);//读文件放入打他数组中,返回读取到的大小                     socket->write(data, msize);//把读取到的data数据发送给服务器                     currentlen += msize;//实时获取当前发送的文件大小                     ui.progressBar->setValue(currentlen *100 / allLength);//更新界面进度条                 } while (currentlen < allLength);//当发送文件等于文件大小时,发送完毕,循环结束             }             });      }     else     {         ui.textEdit->append("连接服务器失败!");     } } //选择文件事件 void QTcpClient::on_btn_choose_clicked() {     QString path = QFileDialog::getOpenFileName(this, "打开文件", "", "(*.*)");     ui.label_path->setText(path); } //发送文件事件 void QTcpClient::on_btn_open_clicked() {     QFileInfo info(ui.label_path->text());     //用QFileInfo::fileName,size获取文件名和大小 格式:文件名&大小     //服务器用该格式解析文件名和大小     QString head = QString("%1&%2").arg(info.fileName()).arg(info.size());     //将该格式发送给服务器 toUtf8:QString转QByteArray或char类型     socket->write(head.toUtf8());  }
  效果展示:

太保副总裁发展互联网业务是太平洋健康险当期的重要任务中国太平洋保险视觉中国资料图11月17日,中国太保副总裁太平洋健康险董事长马欣在发布会上表示,发展互联网业务成为健康险公司当期的重要任务,同时我们也着眼未来,通过深度整合创新科技医永恒岛之彩虹回忆隐藏地图刷怪篇HELLO小伙伴们你们的纯爱战士同学又给大家带来干货了今天给大家带来的是史诗野怪隐藏地图小伙伴们是不是在烦恼挂机刷野怪的时候抢不过人家呢那么本篇文章一定要仔细看哦首先第一个地方大家实力认证!瑞数信息入选网络安全国产化替代甄选厂商榜单今日,斯元商业咨询正式发布了网络安全科技供应链报告厂商成分分析及国产化替代指南CyberSecurityTechnologySupplyChainReportVendorCompo路透社华尔街亿万富翁私募老板被指控在性交易大亨豪宅强奸妇女中国小康网11月29日讯老马周一,私募股权公司ApolloGlobalManagementInc(APO。N)的联合创始人亿万富翁莱昂布莱克(LeonBlack)被一名女子起诉。该云南首富与烟草反腐作者戚师近日,国内锂电池隔膜龙头云南恩捷新材料股份有限公司发布公告称,该公司董事长李晓明副董事长兼总经理李晓华因相关事项被公安机关指定居所监视居住,相关事项尚待进一步调查。一石激起美股开盘道指跌近200点中概股多下跌拼多多逆势涨13金融界11月28日消息,投资者关注日内经济数据及美联储官员讲话,同时疫情担忧以及欧洲主要股市纷纷下挫拖累投资者做多信心,美股在纳斯达克走低拖累下未能延续前一周强势表现集体低开,道指三人行题库精简版第三辑,普及航天知识啦第1题距离酒泉卫星发射中心发射场最近的测控站是。正确答案东风站2。火箭运输到发射场的三种方式公路运输铁路运输海上运输,其中的振动环境优于其他运输方式,可以很好地保证火箭内部设备的安微光盛典女星生图金晨脸歪,赵丽颖发腮,赵露思胖成大饼脸2022年还有一个月就接近尾声了,各大品牌们也终于按耐不住,要祭出自己的大招了。11月29日,微博视界大会微光盛典首先发招,邀请了众多的时尚明星,网友们又可以一饱眼福了。下面就欣赏初中生作文扬帆再启航上海市宝山区教育学院附属中学张睿衡扬帆再启航作者张睿衡望着载着爸爸的飞机像一条潜游的鱼,穿梭进澎湃的云海中,消失不见。白杨树在我和妈妈的身后沙沙作响,我再也忍不住了,眼中的泪水终于夺眶而出。清晨一缕阳光穿过窗户映照孤独,是最昂贵的自由庄子说独往独来,是谓独有。独有之人,是谓至贵。是孤独让一个人变得出众,而不是合群。和别人在一起,我们总处于社会状态只有在孤独中,我们才接近自然状态。孤独是自己走向自己。当我们不用被被兰州人私藏的11个宝贝!但没人敢夸?今天我来兰州,是大西北的腰杆子。荒漠戈壁,雪山高原,瘦骨嶙峋的黄土坡,温润宽厚的河谷地,你能想到的所有意象都与兰州有关,间接或直接。铁马,秋风,塞北。兰州的土地没有一寸未尝被战马踏过,因为
连拿美洲杯与世界杯!金手套大马丁为何难入豪门?4大原因解析作为阿根廷连拿美洲杯与世界杯的重要功臣,大马丁在卡塔尔世界杯上力压布努等人拿到了金手套奖。在阿森纳蹉跎10年后,大马丁在俱乐部与国家队都迎来了双重的救赎,但为何在世界杯后的冬窗,关活成自己最讨厌的样子?爆料称苹果Mac将支持触摸屏1月12日,有知情人士透露,苹果正在开发支持触控屏的Mac电脑,最快2025年有望对公众亮相。对于这一传闻,苹果方面暂时未置可否。按照曝光的苹果开发计划,触摸屏将率先出现在MacB新春走基层丨新田发展桑蚕产业打造致富新丝路村民抢抓晴好天气,忙着栽种桑树苗。红网时刻新闻1月12日讯(通讯员黄新)乡村振兴,产业兴旺是关键。在推进巩固拓展脱贫攻坚成果与乡村振兴有效衔接过程中,新田县积极探索经济效益高的产业新春走基层政企打出组合拳稳岗优工促生产视频加载中央广网宁波1月12日消息(记者俞烨通讯员史宇健)为确保春节期间企业有序生产,稳就业保订单,企业和政府推出真金白银的补贴和暖意浓浓的公共服务,鼓励劳动者坚守岗位,稳定工厂生再次看到火葬场全过程千万别说你有钱一个很著名的实业家,每隔一段时间,他会带着妻儿去火葬场看看。有人不解,问其原因。实业家说,只要到了火葬场,你浮躁的心就会很快安静下来,把名利和财富都会看得很淡。才能做到置身于喧嚣浮冷水江公安集中开展2023年110宣传日活动红网时刻娄底1月10日讯(通讯员谢继长)2023年1月10日,在第37个110宣传日和第三个警察节到来之际,冷水江公安提前谋划精心组织,多警种联合开展矢志不渝110,新征程上保安宁想夸人却只会说666?超六成受访青年担心过度使用网络流行语会冲击传统语言文化中青报中青网记者孙山实习生肖平华网络流行语因生动活泼的特点,受到年轻人的喜爱,但不分场合地过度使用网络流行语,也会带来负面影响。近日,中国青年报社社会调查中心联合问卷网(wenju隋文静将中国舞蹈等优秀传统文化与冰雪运动融合发展新华网北京1月11日电北京冬奥会花样滑冰双人滑冠军隋文静日前在氪体体育行业峰会上发表女性,诠释体育力量主题演讲时表示,在北京舞蹈学院学习坚定了自己将中国舞蹈等优秀传统文化与冰雪运动塞拉斯传统控卫都是传球第一小波特更符合现代控卫的要求直播吧1月11日讯火箭主帅塞拉斯本周接受采访时谈到了本队后卫小凯文波特,塞拉斯认为当今联盟控卫发展的趋势已不像过去那样,强调以传球优先。当你想想过去的(传统)控卫时,小波特显然不是几个人就敢去乌兹别克抓国王?一个被低估的人物上官桀李广利大军猛攻贵山城时,另一支军队正在200里外的郁成(今吉尔吉斯斯坦乌兹根)城下。郁成城东高西低,东部海拔约1000米,西部海拔约800米。郁成王接到大宛王求援令,一直想去解围,十五运会竞赛规程总则公布陕西健儿吹响备战号角陕西竞走队扎实开展冬训备战国家体育总局日前印发了中华人民共和国第十五届运动会竞赛规程总则(以下简称竞赛规程总则),本届全运会竞赛大项初步设置34个,另外还将根据2028年洛杉矶奥运