大地资源网视频在线观看新浪,日本春药精油按摩系列,成人av骚妻潮喷,国产xxxx搡xxxxx搡麻豆

您現(xiàn)在的位置:智能制造網(wǎng)>技術(shù)中心>QT TCP下的socket編程

直播推薦

更多>

企業(yè)動(dòng)態(tài)

更多>

推薦展會(huì)

更多>

QT TCP下的socket編程

2013年11月07日 19:34:07人氣:1546來(lái)源:上海安嵌信息科技有限公司

QTcpSocket 和 QTcpServer類實(shí)現(xiàn)了Qt的Tcp客戶端和服務(wù)器。
tcp是一個(gè)流式協(xié)議。對(duì)于應(yīng)用程序來(lái)說(shuō),數(shù)據(jù)是一個(gè)很長(zhǎng)的流,有點(diǎn)像一個(gè)巨大的文件。
搞成此的協(xié)議建立在面向塊的tcp協(xié)議(Block-oriented)或面向行(Line-oriented )的tcp協(xié)議上。

面向塊的tcp協(xié)議,數(shù)據(jù)被當(dāng)作一個(gè)2進(jìn)制的塊來(lái)傳輸。沒每一個(gè)塊被當(dāng)作一個(gè)定義了大小的,后面跟隨了數(shù)據(jù)的字段。
面向行的tcp協(xié)議,數(shù)據(jù)被當(dāng)作一個(gè)文本文件的一行。一個(gè)傳輸終止于一個(gè)新的行的到來(lái)。

QTcpSocket 繼承自 QIODevice,所以它可以從 QDataStream 或 QTextStream中讀取或?qū)懭霐?shù)據(jù)。

從文件讀數(shù)據(jù)和從網(wǎng)絡(luò)上讀數(shù)據(jù)有一個(gè)明顯的不同點(diǎn): 我們必須保證用“>> ”操作符讀取數(shù)據(jù)時(shí) ,已經(jīng)從另一方接收了足夠的數(shù)據(jù)。如果你這樣做了,那么一個(gè)失敗的結(jié)果是:行為未定義。

我們來(lái)看一個(gè)使用block-oriented tcp協(xié)議的服務(wù)器和客戶端的代碼。

 

用戶填寫行程的起始地,目的地,日期等,服務(wù)器返回符合要求的行程。

界面用QDesigner設(shè)計(jì)的。叫做“tripplanner.ui”。

請(qǐng)使用uic工具轉(zhuǎn)換。

include "ui_tripplanner.h"
class TripPlanner : public QDialog, public Ui::TripPlanner
{
    Q_OBJECT
public:
    TripPlanner(QWidget *parent = 0);
private slots:
    void connectToServer();
    void sendRequest();
    void updateTableWidget();
    void stopSearch();
    void connectionClosedByServer();
    void error();
private:
    void closeConnection();
    QTcpSocket tcpSocket;
    quint16 nextBlockSize;
};

tcpSocket變量是QTcpSocket 類型,用來(lái)建立一個(gè)tcp連接。

當(dāng)需要提起從服務(wù)器傳遞來(lái)的數(shù)據(jù)塊時(shí),nextBlockSize將被使用。

TripPlanner::TripPlanner(QWidget *parent): QDialog(parent){setupUi(this);QDateTime dateTime = QDateTime::currentDateTime();dateEdit->setDate(dateTime.date());timeEdit->setTime(QTime(dateTime.time().hour(), 0));progressBar->hide();progressBar->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Ignored);tableWidget->verticalHeader()->hide();tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);connect(searchButton, SIGNAL(clicked()),this, SLOT(connectToServer()));connect(stopButton, SIGNAL(clicked()), this, SLOT(stopSearch()));connect(&tcpSocket, SIGNAL(connected()), this, SLOT(sendRequest()));connect(&tcpSocket, SIGNAL(disconnected()),this, SLOT(connectionClosedByServer()));connect(&tcpSocket, SIGNAL(readyRead()),this, SLOT(updateTableWidget()));connect(&tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(error()));}

構(gòu)造函數(shù)中,我們?cè)O(shè)置時(shí)間控件的默認(rèn)屬性,隱藏progressBar等。 連接tcpSocket的connected(), disconnected(), readyRead(), error(QAbstractSocket::SocketError)信號(hào)到私有的槽。

void TripPlanner::connectToServer(){tcpSocket.connectToHost("tripserver.zugbahn.de", 6178);tableWidget->setRowCount(0);searchButton->setEnabled(false);stopButton->setEnabled(true);statusLabel->setText(tr("Connecting to server..."));progressBar->show();nextBlockSize = 0;}當(dāng)用戶點(diǎn)擊searchButton時(shí),connectToServer()槽將被執(zhí)行。 它使用tcpSocket.connectToHost建立到 
服務(wù)器的連接。connectToServer()槽立即返回。連接的動(dòng)作實(shí)際發(fā)生在這之后。當(dāng)連接建立成功, 
QTcpSocket 觸發(fā)connected() 信號(hào)。如果失敗,error()信號(hào)被觸發(fā)。 
接著我們?cè)O(shè)置進(jìn)度條以及按鈕的狀態(tài)。 
把nextBlockSize設(shè)置為0.表示我們現(xiàn)在并不知道下一個(gè)接收的數(shù)據(jù)塊的大小。 
   
void TripPlanner::sendRequest(){QByteArray block;QDataStream out(&block, QIODevice::WriteOnly);out.setVersion(QDataStream::Qt_4_1);out << quint16(0) << quint8('S') << fromComboBox->currentText()<< toComboBox->currentText() << dateEdit->date()<< timeEdit->time();if (departureRadioButton->isChecked()) {out << quint8('D');} else {out << quint8('A');}out.device()->seek(0);out << quint16(block.size() - sizeof(quint16));tcpSocket.write(block);statusLabel->setText(tr("Sending request..."));}當(dāng)connected()信號(hào)被觸發(fā),sendRequest()槽被調(diào)用。sendRequest()相愛難過(guò)服務(wù)器發(fā)送一個(gè)請(qǐng)求(tcpSocket.write(block))。 
  
   
  
我們需要在數(shù)據(jù)塊的*個(gè)字段寫入數(shù)據(jù)塊的大小。但是當(dāng)我們些*個(gè)字段時(shí),我們不知道整個(gè)數(shù)據(jù)塊的大小, 
  
所以我們現(xiàn)寫入0(out << quint16(0) ). zui后,當(dāng)數(shù)據(jù)塊填充完畢時(shí),我們計(jì)算數(shù)據(jù)塊的大小,將指針重新 
  
移動(dòng)到QDataStream的開頭(out.device()->seek(0)),重新寫入數(shù)據(jù)塊的大小out << quint16(block.size() - sizeof(quint16))。 
  
zui后,我們發(fā)送數(shù)據(jù)tcpSocket.write(block)。 
  
void TripPlanner::updateTableWidget(){QDataStream in(&tcpSocket);in.setVersion(QDataStream::Qt_4_1);forever {int row = tableWidget->rowCount();if (nextBlockSize == 0) {if (tcpSocket.bytesAvailable() < sizeof(quint16))break;in >> nextBlockSize;}if (nextBlockSize == 0xFFFF) {closeConnection();statusLabel->setText(tr("Found %1 trip(s)").arg(row));break;}if (tcpSocket.bytesAvailable() < nextBlockSize)break;QDate date;QTime departureTime;QTime arrivalTime;quint16 duration;quint8 changes;QString trainType;in >> date >> departureTime >> duration >> changes >> trainType;arrivalTime = departureTime.addSecs(duration * 60);tableWidget->setRowCount(row + 1);QStringList fields;fields << date.toString(Qt::LocalDate)<< departureTime.toString(tr("hh:mm"))<< arrivalTime.toString(tr("hh:mm"))<< tr("%1 hr %2 min").arg(duration / 60).arg(duration % 60)<< QString::number(changes)<< trainType;for (int i = 0; i < fields.count(); ++i)tableWidget->setItem(row, i,new QTableWidgetItem(fields[i]));nextBlockSize = 0;}} 
  
當(dāng)QTcpSocket接收到數(shù)據(jù)時(shí),readyRead()信號(hào)被觸發(fā)。updateTableWidget()槽 就被調(diào)用了。 
  
這里我們用了一個(gè)forever循環(huán),這是必須的!因?yàn)槲覀儫o(wú)法保證一次就接到了所有的數(shù)據(jù)塊。可能,我們只接收到數(shù)據(jù)塊的一個(gè)部分,也可能是全部。 
  
  
   
  
forever循環(huán)是如何工作的呢?如果nextBlockSize是0,表示我們沒有獨(dú)到數(shù)據(jù)塊的大小,我們必須重新讀取它。 數(shù)據(jù)塊的大小字段必須至少讀取sizeof(quint16))字節(jié)才能獲得,如果讀取的數(shù)據(jù)少于sizeof(quint16)),必須重新讀取。 
  
如果數(shù)據(jù)塊大小字段為0xFFFF ,表示服務(wù)器端數(shù)據(jù)發(fā)送完畢,我們停止接收。 
  
   
  
zui后我們?cè)O(shè)置nextBlockSize 為0,表示下一個(gè)數(shù)據(jù)塊的大小還不知道,我們必須接收。 
  
   
  
void TripPlanner::closeConnection(){tcpSocket.close();searchButton->setEnabled(true);stopButton->setEnabled(false);progressBar->hide();}當(dāng)接收到的數(shù)據(jù)塊大小字段的值為0xFFFF,我們關(guān)閉連接。 
  
   
  
  
   
  
void TripPlanner::connectionClosedByServer(){if (nextBlockSize != 0xFFFF)statusLabel->setText(tr("Error: Connection closed by server"));closeConnection();}當(dāng)服務(wù)器斷開連接時(shí),如果我們沒有讀到表示數(shù)據(jù)傳送完畢的 0xFFFF,我們發(fā)出一個(gè)錯(cuò)誤。 
  
   
  
void TripPlanner::error(){statusLabel->setText(tcpSocket.errorString());closeConnection();}顯示錯(cuò)誤。 
  
   
  
主函數(shù): 
  
int main(int argc, char *argv[]){QApplication app(argc, argv);TripPlanner tripPlanner;tripPlanner.show();return app.exec();} 
  
void TripPlanner::stopSearch(){statusLabel->setText(tr("Search stopped"));closeConnection();} 
 如果stopServer按鈕被單擊,我們關(guān)閉連接。
   
接下來(lái),我們看看服務(wù)器端的實(shí)現(xiàn)。 
class TripServer : public QTcpServer{Q_OBJECTpublic:TripServer(QObject *parent = 0);private:void incomingConnection(int socketId);};服務(wù)器端重新實(shí)現(xiàn)incomingConnection方法。當(dāng)客戶端嘗試連接到服務(wù)器的監(jiān)聽端口時(shí),incomingConnection方法被觸發(fā)。 
void TripServer::incomingConnection(int socketId){ClientSocket *socket = new ClientSocket(this);socket->setSocketDescriptor(socketId);} 
  
   
  
   
  
   
  
   
  
class ClientSocket : public QTcpSocket{Q_OBJECTpublic:ClientSocket(QObject *parent = 0);private slots:void readClient();private:void generateRandomTrip(const QString &from, const QString &to,const QDate &date, const QTime &time);quint16 nextBlockSize;}; 
  
  
ClientSocket::ClientSocket(QObject *parent): QTcpSocket(parent){connect(this, SIGNAL(readyRead()), this, SLOT(readClient()));connect(this, SIGNAL(disconnected()), this, SLOT(deleater()));nextBlockSize = 0;} 
  
   
  
void ClientSocket::readClient(){QDataStream in(this);in.setVersion(QDataStream::Qt_4_1);if (nextBlockSize == 0) {if (bytesAvailable() < sizeof(quint16))return;in >> nextBlockSize;}if (bytesAvailable() < nextBlockSize)return;quint8 requestType;QString from;QString to;QDate date;QTime time;quint8 flag;in >> requestType;if (requestType == 'S') {in >> from >> to >> date >> time >> flag;srand(from.length() * 3600 + to.length() * 60 + time.hour());int numTrips = rand() % 8;for (int i = 0; i < numTrips; ++i)generateRandomTrip(from, to, date, time);QDataStream out(this);out << quint16(0xFFFF);}close();} 
  
void ClientSocket::generateRandomTrip(const QString & ,const QString & , const QDate &date, const QTime &time){QByteArray block;QDataStream out(&block, QIODevice::WriteOnly);out.setVersion(QDataStream::Qt_4_1);quint16 duration = rand() % 200;out << quint16(0) << date << time << duration << quint8(1)<< QString("InterCity");out.device()->seek(0);out << quint16(block.size() - sizeof(quint16));write(block);} 
  
  
int main(int argc, char *argv[]){QApplication app(argc, argv);TripServer server;if (!server.listen(QHostAddress::Any, 6178)) {cerr << "Failed to bind to port" << endl;return 1;}QPushButton quitButton(QObject::tr("&Quit"));quitButton.setWindowTitle(QObject::tr("Trip Server"));QObject::connect(&quitButton, SIGNAL(clicked()),&app, SLOT(quit()));quitButton.show();return app.exec();} 
全年征稿/資訊合作 聯(lián)系郵箱:1271141964@qq.com

免責(zé)聲明

  • 凡本網(wǎng)注明"來(lái)源:智能制造網(wǎng)"的所有作品,版權(quán)均屬于智能制造網(wǎng),轉(zhuǎn)載請(qǐng)必須注明智能制造網(wǎng),http://www.xashilian.com。違反者本網(wǎng)將追究相關(guān)法律責(zé)任。
  • 企業(yè)發(fā)布的公司新聞、技術(shù)文章、資料下載等內(nèi)容,如涉及侵權(quán)、違規(guī)遭投訴的,一律由發(fā)布企業(yè)自行承擔(dān)責(zé)任,本網(wǎng)有權(quán)刪除內(nèi)容并追溯責(zé)任。
  • 本網(wǎng)轉(zhuǎn)載并注明自其它來(lái)源的作品,目的在于傳遞更多信息,并不代表本網(wǎng)贊同其觀點(diǎn)或證實(shí)其內(nèi)容的真實(shí)性,不承擔(dān)此類作品侵權(quán)行為的直接責(zé)任及連帶責(zé)任。其他媒體、網(wǎng)站或個(gè)人從本網(wǎng)轉(zhuǎn)載時(shí),必須保留本網(wǎng)注明的作品來(lái)源,并自負(fù)版權(quán)等法律責(zé)任。
  • 如涉及作品內(nèi)容、版權(quán)等問(wèn)題,請(qǐng)?jiān)谧髌钒l(fā)表之日起一周內(nèi)與本網(wǎng)聯(lián)系,否則視為放棄相關(guān)權(quán)利。

<
更多 >

工控網(wǎng)機(jī)器人儀器儀表物聯(lián)網(wǎng)3D打印工業(yè)軟件金屬加工機(jī)械包裝機(jī)械印刷機(jī)械農(nóng)業(yè)機(jī)械食品加工設(shè)備制藥設(shè)備倉(cāng)儲(chǔ)物流環(huán)保設(shè)備造紙機(jī)械工程機(jī)械紡織機(jī)械化工設(shè)備電子加工設(shè)備水泥設(shè)備海洋水利裝備礦冶設(shè)備新能源設(shè)備服裝機(jī)械印染機(jī)械制鞋機(jī)械玻璃機(jī)械陶瓷設(shè)備橡塑設(shè)備船舶設(shè)備電子元器件電氣設(shè)備


我要投稿
  • 投稿請(qǐng)發(fā)送郵件至:(郵件標(biāo)題請(qǐng)備注“投稿”)1271141964.qq.com
  • 聯(lián)系電話0571-89719789
工業(yè)4.0時(shí)代智能制造領(lǐng)域“互聯(lián)網(wǎng)+”服務(wù)平臺(tái)
智能制造網(wǎng)APP

功能豐富 實(shí)時(shí)交流

智能制造網(wǎng)小程序

訂閱獲取更多服務(wù)

微信公眾號(hào)

關(guān)注我們

抖音

智能制造網(wǎng)

抖音號(hào):gkzhan

打開抖音 搜索頁(yè)掃一掃

視頻號(hào)

智能制造網(wǎng)

公眾號(hào):智能制造網(wǎng)

打開微信掃碼關(guān)注視頻號(hào)

快手

智能制造網(wǎng)

快手ID:gkzhan2006

打開快手 掃一掃關(guān)注
意見反饋
關(guān)閉
企業(yè)未開通此功能
詳詢客服 : 0571-87858618
主站蜘蛛池模板: 禄劝| 雷州市| 民勤县| 湟源县| 新余市| 瑞安市| 苗栗市| 天镇县| 嘉鱼县| 电白县| 确山县| 遂宁市| 迁西县| 土默特右旗| 泸州市| 蒲城县| 屯昌县| 湘潭市| 南雄市| 株洲县| 醴陵市| 富锦市| 卓资县| 涞源县| 志丹县| 清远市| 玉环县| 图们市| 安新县| 金昌市| 武宣县| 辽中县| 合山市| 石景山区| 彩票| 红安县| 东山县| 双鸭山市| 紫阳县| 青浦区| 郴州市|