一次完整的抓包分析 Reserved TCP/IP Port List

本文提供了TCP/IP协议中已注册并预留的端口列表,详细介绍了0至1024之间的知名端口号及其对应的服务,这些端口由IANA保留用于特权服务。

抓包如图所示:

本机IP被粉色遮住。。。

http://www.skynet.ie/~colinmac/Programming/port_listing.html

Reserved TCP/IP Port List

This is an complete list of the TCP/IP ports that are IANA registered and so are not for general use in network programming. Port numbers range from 0 to 65536, but only ports numbers 0 to 1024 are reserved for privileged services and designated as well-known ports.

0Reserved
1tcpmuxTCP Port Service Multiplexer
2compressnetManagement Utility
3compressnetCompression Process
5rjeRemote Job Entry
7echoEcho
9discardDiscard
11systatActive Users
13daytimeDaytime
17qotdQuote of the Day
18mspMessage Send Protocol
19chargenCharacter Generator
20ftp-dataFile Transfer [Default Data]
21ftpFile Transfer [Control]
22sshSSH Remote Login Protocol
23telnetTelnet
24any private mail system
25smtpSimple Mail Transfer
27nsw-feNSW User System FE
29msg-icpMSG ICP
31msg-authMSG Authentication
33dspDisplay Support Protocol
35any private printer server
37timeTime
38rapRoute Access Protocol
39rlpResource Location Protocol
41graphicsGraphics
42nameHost Name Server
42nameserverHost Name Server
43nicnameWho Is/WHOIS
44mpm-flagsMPM FLAGS Protocol
45mpmMessage Processing Module [recv]
46mpm-sndMPM [default send]
47ni-ftpNI FTP
48auditdDigital Audit Daemon
49tacacsLogin Host Protocol (TACACS)
50re-mail-ckRemote Mail Checking Protocol
51la-maintIMP Logical Address Maintenance
52xns-timeXNS Time Protocol
53domainDomain Name Server
54xns-chXNS Clearinghouse
55isi-glISI Graphics Language
56xns-authXNS Authentication
57any private terminal access
58xns-mailXNS Mail
59any private file service
60Unassigned
61ni-mailNI MAIL
62acasACA Services
63whois++whois++
64coviaCommunications Integrator (CI)
65tacacs-dsTACACS-Database Service
66sql*netOracle SQL*NET
67bootpsBootstrap Protocol Server
68bootpcBootstrap Protocol Client
69tftpTrivial File Transfer
70gopherGopher
71netrjs-1Remote Job Service
72netrjs-2Remote Job Service
73netrjs-3Remote Job Service
74netrjs-4Remote Job Service
75any private dial out service
76deosDistributed External Object Store
77any private RJE service
78vettcpvettcp
79fingerFinger
80httpWorld Wide Web HTTP
80wwwWorld Wide Web HTTP
80www-httpWorld Wide Web HTTP
81hosts2-nsHOSTS2 Name Server
82xferXFER Utility
83mit-ml-devMIT ML Device
84ctfCommon Trace Facility
85mit-ml-devMIT ML Device
86mfcobolMicro Focus Cobol
87any private terminal link
88kerberosKerberos
89su-mit-tgSU/MIT Telnet Gateway
90dnsixDNSIX Securit Attribute Token Map
91mit-dovMIT Dover Spooler
92nppNetwork Printing Protocol
93dcpDevice Control Protocol
94objcallTivoli Object Dispatcher
95supdupSUPDUP
96dixieDIXIE Protocol Specification
3687simple-pushsimple-push
3688simple-push-ssimple-push Secure
3689daapDigital Audio Access Protocol
3690svnSubversion
其余省略自己去查表。。。
#include "debug.h" #include "ui_debug.h" #include "multhread.h" #include <QThreadPool> Debug::Debug(QWidget *parent) : QMainWindow(parent) , ui(new Ui::Debug) { ui->setupUi(this); showNetworkCard(); //初始化 ui->NetworkDisplay->horizontalHeader()->setStyleSheet( "QHeaderView::section {" " background-color: #e1e1e1;" " padding: 4px 8px;" " border: none;" " font-weight: bold;" "}" ); ui->NetworkDisplay->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter); //保持表头的字符在最左边 ui->Filter->setPlaceholderText ("输入过滤表达式,如:tcp.port == 80"); ui->NetworkDisplay->setShowGrid (false); //去除竖着的网格线 ui->NetworkDisplay->verticalHeader ()->setVisible (false); //去除自带的编号 ui->NetworkDisplay->setSelectionBehavior (QAbstractItemView::SelectRows); //选择一整行 ui->NetworkParse->setHeaderHidden (true); //隐藏树形结构的头 ui->actionrun_stop->setIcon(QIcon(":/source/start.png")); //把工具栏中的开始按钮图形初始化 statusBar ()->showMessage ("欢迎访问!"); countNumber = 0; //设置数据包当前个数,初始化为0 numberRow = -1; //初始化为-1 ui->toolBar->setMovable (false); //固定工具栏 ui->toolBar->addAction(ui->actionrun_stop); //工具栏中加入开始按钮 ui->NetworkDisplay->setColumnCount (7); //初始化表头 ui->NetworkDisplay->verticalHeader ()->setDefaultSectionSize (30); //设置widget的行高 QStringList title = {"序号" , "时间", "源IP地址" , "目的IP地址", "协议", "数据包总长度", "数据包信息(端口、数据包内容长度)"}; ui->NetworkDisplay->setHorizontalHeaderLabels (title); ui->NetworkDisplay->setColumnWidth (0, 50); ui->NetworkDisplay->setColumnWidth (1, 150); ui->NetworkDisplay->setColumnWidth (2, 300); ui->NetworkDisplay->setColumnWidth (3, 300); ui->NetworkDisplay->setColumnWidth (4, 100); ui->NetworkDisplay->setColumnWidth (5, 100); ui->NetworkDisplay->setColumnWidth (6, 1000); readOnlyDelegate = new ProtocolDelegate(); //创建一个“只读”控制器,但是没有父对象,所以需要在析构函数中自己删除 ui->NetworkDisplay->setItemDelegate (readOnlyDelegate); udpsocket = new QUdpSocket; multhread *sunThread = new multhread; //新建一个线程 static bool flag = false; //用于判断是否点击 htwj_content = new infdisplay(); //实例化软件类,根据不同结构体去进行不同展示 htwj_content->setWidgets (ui->NetworkParse, ui->ContentParse); QThread *parseThread = new QThread(this); parsethread *parse = new parsethread(this); parse->moveToThread (parseThread); //开启子线程 connect(ui->actionrun_stop, &QAction::triggered, this, [=](){ flag = !flag; if(flag){ //在进入抓包前询问是否要保存文件,后续加逻辑 if(!currentDevice){ QMessageBox::warning(this, "错误", "请选择一个网卡设备"); flag = !flag; return; } //初始化操作 ui->NetworkDisplay->clearContents (); //开始一轮新的捕获前清空 ui->NetworkParse->clear (); //清空 ui->ContentParse->clear (); ui->NetworkDisplay->setRowCount (0); //设置行数 countNumber = 0; numberRow = -1; //进行内存清空的操作,因为抓包使用了memcpy,所以需要去主动释放内存 int dataSize = this->pData.size (); for(int i = 0; i < dataSize; i++){ free((char*)pData[i].pkt_content); this->pData[i].pkt_content = nullptr; //防止出现野指针 } QVector<DataPackage>().swap(pData); //用空的容器和pData进行内存交换来释放内存 //开始 int res = Capture(); //调试是否正确捕捉到 qDebug() << "Capture result:" << res; if (point) qDebug() << "Device opened:" << currentDevice->name; else qDebug() << "Error:" << errBuf; if(res != -1 && point){ //若网卡设备没问题,且当前设备指针不为空,则开始捕获分析数据包 parseThread->start (); sunThread->setPointer(point); sunThread->setFlag(); sunThread->start(); ui->actionrun_stop->setIcon(QIcon(":/source/stop.png")); ui->NetworkCardBox->setEnabled(false); //开始捕获一张网卡的数据包后,在不暂停前不能更换网卡,所以列表无法选择 }else{ flag = !flag; countNumber = 0; numberRow = -1; } }else{ //停止 //释放掉线程 sunThread->resetFlag(); sunThread->quit(); sunThread->wait(); ui->actionrun_stop->setIcon(QIcon(":/source/start.png")); ui->NetworkCardBox->setEnabled(true); pcap_close(point); //释放掉指针资源 point = nullptr; //开一个新的线程用来写文件 } }); //抓包线程给主线程发信号以后,目前由主线程进行解析 connect (sunThread, &multhread::send, this, &Debug::HandleMessage); //高亮的ui设置 connect(ui->ContentParse, &QPlainTextEdit::cursorPositionChanged, [this](){ htwj_content->locateFromHexClick(ui->ContentParse->textCursor().position()); }); connect(ui->NetworkParse, &QTreeWidget::itemClicked, [this](QTreeWidgetItem *item){ htwj_content->highlightFromTree(item); }); connect(ui->NetworkParse, &QTreeWidget::currentItemChanged, [this](QTreeWidgetItem *item){ htwj_content->highlightFromTree(item); }); //解析包 connect(this, &Debug::sendClickPackage, parse, &parsethread::parsePackage); connect(parse, &parsethread::sendUI, this, [=](QList<QTreeWidgetItem*> items, QByteArray rawData, infdisplay *m_htwj_content){ ui->NetworkParse->addTopLevelItems (items); ui->ContentParse->setPlainText (rawData.toHex (' ')); htwj_content = m_htwj_content; }); } Debug::~Debug() { int dataSize = pData.size(); for(int i = 0; i < dataSize; i++){ free((char*)(this->pData[i].pkt_content)); this->pData[i].pkt_content = nullptr; } QVector<DataPackage>().swap(pData); delete ui; } //显示所有机器上的网卡设备,来确认选择哪个网卡进行抓包 void Debug::showNetworkCard(){ //通过导入的函数去判断是否找到了所有的网卡 int n = pcap_findalldevs(&all_device, errBuf); //此处会获取到一个所有网卡的列表,并把首地址给放到all_device中 if(n == -1){ //正常获取成功时,n不为-1,所以当n为-1时报错 ui->NetworkCardBox->addItem("error:" + (QString)errBuf); }else{ //把所有获取到的设备都加载到NetworkCardBox中 ui->NetworkCardBox->clear(); ui->NetworkCardBox->addItem("选择一个网卡设备进行抓包!"); for( currentDevice = all_device; currentDevice != nullptr; currentDevice = currentDevice->next){ QString device_name = currentDevice->name; //获取设备名称 device_name.replace("\\Device\\", ""); //把前缀替换掉 QString device_Des = currentDevice->description; //获取设备描述 QString item = device_name + device_Des; ui->NetworkCardBox->addItem(item); } } } //获取当下盒子里我选择的网卡是哪一张,此时的currentDevice指向我当前选择的那张网卡了,我再进行操作 void Debug::on_NetworkCardBox_currentIndexChanged(int index) { int i = 0; if(index != 0){ //如果index是0说明没有选择网卡,所以就不需要获取当前网卡 for(currentDevice = all_device; i < index - 1; currentDevice = currentDevice->next){ i++; } } return ; } //抓包,获取到网卡上的网络包 int Debug::Capture(){ if(currentDevice){ point = pcap_open_live(currentDevice->name, 65536, 1, 1000, errBuf); //打开网络设备进行数据包捕获,第二位表示捕获的最大字节数,第三位表示是否启用混杂模式,开启则捕获所有经过网卡的数据包,而不仅是发给本机的,第四位表示超时时间(毫秒) }else{ return -1; } //判断设备是否打开成功 if(!point){ pcap_freealldevs(all_device); //没打开成功就关闭设备 currentDevice = nullptr; //避免出现野指针 return -1; }else{ //不为空则打开成功,捕获自己想要的数据包 int link_type = pcap_datalink(point); if(link_type != DLT_EN10MB && link_type != DLT_NULL && link_type !=DLT_RAW){ //不满足自己的协议就关闭设备,把指针清空 qDebug() << "网卡无法接收到,线程阻塞!"; pcap_close(point); pcap_freealldevs(all_device); currentDevice = nullptr; point = nullptr; return -1; } } statusBar()->showMessage(currentDevice->name); return 0; } //线程信号发送的接收槽函数 //子线程处理完一个网络数据包后会给主线程发送一个信号,此时槽函数将数据填入到窗口中 //因为每一次信号都会触发这个槽函数,所以函数中只需要处理一个数据包就行 void Debug::HandleMessage (DataPackage data){ ui->NetworkDisplay->insertRow(countNumber); //插入新的一行 this->pData.push_back (data); QString type = data.getPackageType (); QColor color; if(type == "tcp"){ color = QColor(255, 255, 200); } else if(type == "udp"){ color = QColor(200, 255, 200); } else if(type == "arp"){ color = QColor(238, 238, 0); } else if(type == "dns"){ color = QColor(144, 144, 144); } else{ color = QColor(255, 218, 185); } //把数据内容根据所需插入到表格中 ui->NetworkDisplay->setItem (countNumber, 0, new QTableWidgetItem(QString ::number (countNumber))); ui->NetworkDisplay->setItem (countNumber, 1, new QTableWidgetItem(data.getTimeStamp ())); ui->NetworkDisplay->setItem (countNumber, 2, new QTableWidgetItem(data.getSource ())); //数据包的源IP或源Mac ui->NetworkDisplay->setItem (countNumber, 3, new QTableWidgetItem(data.getDestination ())); //数据包的目的IP或目的Mac ui->NetworkDisplay->setItem (countNumber, 4, new QTableWidgetItem(type.toUpper ())); ui->NetworkDisplay->setItem (countNumber, 5, new QTableWidgetItem(data.getDataLength ())); ui->NetworkDisplay->setItem (countNumber, 6, new QTableWidgetItem(data.getInfo ())); //设置每一个单元格的背景颜色 for(int i = 0; i < 7; i++) { ui->NetworkDisplay->item(countNumber, i)->setBackground(color); } countNumber++; } //点击网络包后,在下面树形结构中展示网络包的详细内容 void Debug::on_NetworkDisplay_cellClicked(int row, int column){ emit sendClickPackage (row, numberRow, countNumber, pData); } //处理数据包的函数,添加树形结构,存储数据包发送元数据,后续改处理逻辑在这里改就行 // void Debug::handleNetworkSelection (int row, int column){ // if(row == numberRow || row < 0){ // return ; // }else{ // ui->NetworkParse->clear (); // numberRow = row; // //边界判断 // if(numberRow < 0 || numberRow > countNumber) // return; // //Ethernet层的树形结构 // QString desMac = pData[numberRow].getDstMacAddr (); // QString srcMac = pData[numberRow].getSrcMacAddr (); // QString type = pData[numberRow].getMacType (); // QString tree = "Ethernet , Src: " + srcMac + " Dst: " + desMac; // QTreeWidgetItem *item1 = new QTreeWidgetItem(QStringList()<<tree); // ui->NetworkParse->addTopLevelItem (item1); // item1->addChild (new QTreeWidgetItem(QStringList()<< "Destination:" + desMac)); // item1->addChild (new QTreeWidgetItem(QStringList()<< "Source:" + srcMac)); // item1->addChild (new QTreeWidgetItem(QStringList()<< "Type:" + type)); // QString packageType = pData[numberRow].getPackageType (); //获取当前行的上层协议类型 // //处理各种不同协议的树形结构 // //处理ARP包 // if(packageType == "arp"){ // ui->ContentParse->clear (); // QString arpType = pData[numberRow].getArpOperationCode (); // QTreeWidgetItem *item2 = new QTreeWidgetItem(QStringList()<< "Address Resolution Protocol " + arpType); // ui->NetworkParse->addTopLevelItem (item2); // QString HardwareType = pData[numberRow].getArpHardwareType (); // QString protocolType = pData[numberRow].getArpProtocolType (); // QString HardwareLength = pData[numberRow].getArpHardwareLength (); // QString protocolLength = pData[numberRow].getArpProtocolLength (); // QString srcMacAddr = pData[numberRow].getArpSourceEtherAddr (); // QString dstMacAddr = pData[numberRow].getArpDestinationEtherAddr (); // QString srcIpAddr = pData[numberRow].getArpSourceIpAddr (); // QString dstIpAddr = pData[numberRow].getArpDestinationIpAddr (); // item2->addChild (new QTreeWidgetItem(QStringList() << "Hardware Type: " + HardwareType)); // item2->addChild(new QTreeWidgetItem(QStringList()<<"Protocol type:" + protocolType)); // item2->addChild(new QTreeWidgetItem(QStringList()<<"Hardware size:" + HardwareLength)); // item2->addChild(new QTreeWidgetItem(QStringList()<<"Protocol size:" + protocolLength)); // item2->addChild(new QTreeWidgetItem(QStringList()<<"Opcode:" + arpType)); // item2->addChild(new QTreeWidgetItem(QStringList()<<"Sender MAC address:" + srcMacAddr)); // item2->addChild(new QTreeWidgetItem(QStringList()<<"Sender IP address:" + srcIpAddr)); // item2->addChild(new QTreeWidgetItem(QStringList()<<"Target MAC address:" + dstMacAddr)); // item2->addChild(new QTreeWidgetItem(QStringList()<<"Target IP address:" + dstIpAddr)); // return; // } // //处理IP包 // else{ // ui->ContentParse->clear (); // QString srcIp = pData[numberRow].getSrcIpAddr (); // QString dstIp = pData[numberRow].getDstIpAddr (); // QTreeWidgetItem *item3 = new QTreeWidgetItem(QStringList() << "Internet Protocol Version 4, Src: " + srcIp + " , Dst: " + dstIp); // ui->NetworkParse->addTopLevelItem (item3); // QString version = pData[numberRow].getIpVersion (); // QString headerLength = pData[numberRow].getIpHeaderLength (); // QString Tos = pData[numberRow].getIpTos (); // QString totalLength = pData[numberRow].getIpTotalLength (); // QString id = "0x" + pData[numberRow].getIpIdentification (); // QString flags = pData[numberRow].getIpFlag (); // if(flags.size() < 2) //格式化处理,确保是2位十六进制数 // flags = "0" + flags; // flags = "0x" + flags; // QString FragmentOffset = pData[numberRow].getIpFragmentOffset (); // QString ttl = pData[numberRow].getIpTTL (); // QString protocol = pData[numberRow].getIpProtocol (); // QString checksum = "0x" + pData[numberRow].getIpCheckSum(); // int dataLengthofIp = totalLength.toUtf8 ().toInt () - 20; // item3->addChild (new QTreeWidgetItem(QStringList() << "0100.... = version: " + version)); // item3->addChild (new QTreeWidgetItem(QStringList() << "....0101 = Header Length: " + headerLength)); // item3->addChild (new QTreeWidgetItem(QStringList() << "TOS: " + Tos)); // item3->addChild (new QTreeWidgetItem(QStringList() << "Total Length: " + totalLength)); // item3->addChild (new QTreeWidgetItem(QStringList() << "Identification: " + id)); // QString reservedBit = pData[numberRow].getIpReservedBit (); // QString DF = pData[numberRow].getIpDF (); // QString MF = pData[numberRow].getIpMF (); // QString FLAG = ","; // if(reservedBit == "1"){ // FLAG += "ReserverBit"; // } // else if(DF == "1"){ // FLAG += "Don't fragment"; // } // else if(MF == "1"){ // FLAG += "More fragment"; // } // if(FLAG.size() == 1){ // FLAG = ""; // } // QTreeWidgetItem *bitTree = new QTreeWidgetItem(QStringList() << "Flags: " + flags + FLAG); // item3->addChild (bitTree); // QString temp = reservedBit == "1" ? "Set" : "Not set"; // bitTree->addChild (new QTreeWidgetItem(QStringList() << reservedBit + "... .... = Reserved bit:" + temp)); // temp = DF == "1"?"Set":"Not set"; // bitTree->addChild(new QTreeWidgetItem(QStringList()<<"." + DF + ".. .... = Don't fragment:" + temp)); // temp = MF == "1"?"Set":"Not set"; // bitTree->addChild(new QTreeWidgetItem(QStringList()<<".." + MF + ". .... = More fragment:" + temp)); // item3->addChild(new QTreeWidgetItem(QStringList()<<"Fragment Offset:" + FragmentOffset)); // item3->addChild(new QTreeWidgetItem(QStringList()<<"Time to Live:" + ttl)); // item3->addChild(new QTreeWidgetItem(QStringList()<<"Protocol:" + protocol)); // item3->addChild(new QTreeWidgetItem(QStringList()<<"Header checksum:" + checksum)); // item3->addChild(new QTreeWidgetItem(QStringList()<<"Source Address:" + srcIp)); // item3->addChild(new QTreeWidgetItem(QStringList()<<"Destination Address:" + dstIp)); // //处理TCP、TLS和SSL包 // if(packageType == "tcp" || packageType == "tls" || packageType == "ssl"){ // ui->ContentParse->clear (); // } // //可以从这里开始看,反正只发送udp包 // //处理UDP和DNS包 // if(packageType == "udp" || packageType == "dns"){ // ui->ContentParse->clear (); // //infdisplay *htwj_content = new infdisplay(); //实例化软件类,根据不同结构体去进行不同展示 // htwj_content->setWidgets (ui->NetworkParse, ui->ContentParse); // htwj_content->clearFields (); // // qDebug() << "出问题了"; // QString srcPort = pData[numberRow].getUdpSourcePort (); // QString dstPort = pData[numberRow].getUdpDestinationPort (); // QString Length = pData[numberRow].getUdpDataLength (); // QString Checksum = pData[numberRow].getUdpCheckSum (); // QTreeWidgetItem *item4 = new QTreeWidgetItem(QStringList() << "User Datagram Protocol, Src Port: " + srcPort + " Dst Port: " + dstPort); // ui->NetworkParse->addTopLevelItem (item4); // item4->addChild (new QTreeWidgetItem(QStringList() << "Source Port: " + srcPort)); // item4->addChild (new QTreeWidgetItem(QStringList() << "Destination Port: " + dstPort)); // item4->addChild (new QTreeWidgetItem(QStringList() << "Length: " + Length)); // item4->addChild (new QTreeWidgetItem(QStringList() << "Checksum: " + Checksum)); // int udpLength = Length.toUtf8 ().toInt (); // int udp_payLoad = udpLength - 8; // if(udpLength > 0){ // item4->addChild (new QTreeWidgetItem(QStringList() << "UDP PayLoad (" + QString::number (udpLength - 8) + " bytes)")); // } // //处理发送的UDP报文中的信息,重新添加一个树形结构,展示各种结构体,并且把原始数据转换为16进制放到右边框中 // QTreeWidgetItem *htwj_item = new QTreeWidgetItem(QStringList() << "对应发送的原始数据"); // ui->NetworkParse->addTopLevelItem (htwj_item); // const u_char *current_pkt_content = pData[numberRow].pkt_content; //获取数据包原始内容 // //!!!!!!!!!!!!这里还得改本地包和网络包的区别 // QByteArray rawData = QByteArray(reinterpret_cast<const char*>(current_pkt_content + 4 + 20 + 8), udp_payLoad); //把const u_char转换为QByteArray,方便以十六进制形式展示 // ui->ContentParse->setPlainText (rawData.toHex (' ')); //转换为十六进制,并用空格来分隔 // //目前根据结构体的字节长度去判断是哪种结构体类型 // switch(udp_payLoad){ // case 44:{ // QStringList sceneInfo = htwj_content->getSceneInformation (current_pkt_content); // for (const QString &info : sceneInfo) { // htwj_item->addChild(new QTreeWidgetItem(QStringList() << info)); // } // } // case 82:{ // QStringList platformInfo = htwj_content->getPlatformInformation (current_pkt_content); // for (const QString &info : platformInfo) { // htwj_item->addChild(new QTreeWidgetItem(QStringList() << info)); // } // } // } // } // } // } // } void Debug::on_FilterButton_clicked() { //获取过滤框中内容 QString filterText = ui->Filter->text().trimmed(); //逐行去筛选 if(filterText.isEmpty ()){ for(int row = 0; row < ui->NetworkDisplay->rowCount(); row++){ ui->NetworkDisplay->setRowHidden(row, false); } return; } filter = new FilterParse; if (!filter) { qDebug() << "FilterParse creation failed!"; return; }else{ qDebug() << "FilterParse creation succeed!"; } qDebug() << ui->NetworkDisplay->rowCount(); for(int row = 0; row < ui->NetworkDisplay->rowCount(); row++){ //因为解析器中match的值是true的时候需要显示,但是设置只能设置隐形,所以初始值为false bool match = false; DataPackage data = pData[row]; match = filter->parse(filterText, data); //qDebug() << match; ui->NetworkDisplay->setRowHidden(row, !match); } } //用于实现键盘上下切换行时,下方的展示格也同步变换 void Debug::on_NetworkDisplay_currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn) { Q_UNUSED(previousRow); Q_UNUSED(previousColumn); //handleNetworkSelection (currentRow, currentColumn); } 这是主线程,问题在哪
最新发布
07-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值