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

您現在的位置:智能制造網>技術中心>QT TCP下的socket編程

直播推薦

更多>

企業動態

更多>

推薦展會

更多>

QT TCP下的socket編程

2013年11月07日 19:34:07人氣:1550來源:上海安嵌信息科技有限公司

QTcpSocket 和 QTcpServer類實現了Qt的Tcp客戶端和服務器。
tcp是一個流式協議。對于應用程序來說,數據是一個很長的流,有點像一個巨大的文件。
搞成此的協議建立在面向塊的tcp協議(Block-oriented)或面向行(Line-oriented )的tcp協議上。

面向塊的tcp協議,數據被當作一個2進制的塊來傳輸。沒每一個塊被當作一個定義了大小的,后面跟隨了數據的字段。
面向行的tcp協議,數據被當作一個文本文件的一行。一個傳輸終止于一個新的行的到來。

QTcpSocket 繼承自 QIODevice,所以它可以從 QDataStream 或 QTextStream中讀取或寫入數據。

從文件讀數據和從網絡上讀數據有一個明顯的不同點: 我們必須保證用“>> ”操作符讀取數據時 ,已經從另一方接收了足夠的數據。如果你這樣做了,那么一個失敗的結果是:行為未定義。

我們來看一個使用block-oriented tcp協議的服務器和客戶端的代碼。

 

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

界面用QDesigner設計的。叫做“tripplanner.ui”。

請使用uic工具轉換。

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 類型,用來建立一個tcp連接。

當需要提起從服務器傳遞來的數據塊時,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()));}

構造函數中,我們設置時間控件的默認屬性,隱藏progressBar等。 連接tcpSocket的connected(), disconnected(), readyRead(), error(QAbstractSocket::SocketError)信號到私有的槽。

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;}當用戶點擊searchButton時,connectToServer()槽將被執行。 它使用tcpSocket.connectToHost建立到 
服務器的連接。connectToServer()槽立即返回。連接的動作實際發生在這之后。當連接建立成功, 
QTcpSocket 觸發connected() 信號。如果失敗,error()信號被觸發。 
接著我們設置進度條以及按鈕的狀態。 
把nextBlockSize設置為0.表示我們現在并不知道下一個接收的數據塊的大小。 
   
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..."));}當connected()信號被觸發,sendRequest()槽被調用。sendRequest()相愛難過服務器發送一個請求(tcpSocket.write(block))。 
  
   
  
我們需要在數據塊的*個字段寫入數據塊的大小。但是當我們些*個字段時,我們不知道整個數據塊的大小, 
  
所以我們現寫入0(out << quint16(0) ). zui后,當數據塊填充完畢時,我們計算數據塊的大小,將指針重新 
  
移動到QDataStream的開頭(out.device()->seek(0)),重新寫入數據塊的大小out << quint16(block.size() - sizeof(quint16))。 
  
zui后,我們發送數據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;}} 
  
當QTcpSocket接收到數據時,readyRead()信號被觸發。updateTableWidget()槽 就被調用了。 
  
這里我們用了一個forever循環,這是必須的!因為我們無法保證一次就接到了所有的數據塊。可能,我們只接收到數據塊的一個部分,也可能是全部。 
  
  
   
  
forever循環是如何工作的呢?如果nextBlockSize是0,表示我們沒有獨到數據塊的大小,我們必須重新讀取它。 數據塊的大小字段必須至少讀取sizeof(quint16))字節才能獲得,如果讀取的數據少于sizeof(quint16)),必須重新讀取。 
  
如果數據塊大小字段為0xFFFF ,表示服務器端數據發送完畢,我們停止接收。 
  
   
  
zui后我們設置nextBlockSize 為0,表示下一個數據塊的大小還不知道,我們必須接收。 
  
   
  
void TripPlanner::closeConnection(){tcpSocket.close();searchButton->setEnabled(true);stopButton->setEnabled(false);progressBar->hide();}當接收到的數據塊大小字段的值為0xFFFF,我們關閉連接。 
  
   
  
  
   
  
void TripPlanner::connectionClosedByServer(){if (nextBlockSize != 0xFFFF)statusLabel->setText(tr("Error: Connection closed by server"));closeConnection();}當服務器斷開連接時,如果我們沒有讀到表示數據傳送完畢的 0xFFFF,我們發出一個錯誤。 
  
   
  
void TripPlanner::error(){statusLabel->setText(tcpSocket.errorString());closeConnection();}顯示錯誤。 
  
   
  
主函數: 
  
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按鈕被單擊,我們關閉連接。
   
接下來,我們看看服務器端的實現。 
class TripServer : public QTcpServer{Q_OBJECTpublic:TripServer(QObject *parent = 0);private:void incomingConnection(int socketId);};服務器端重新實現incomingConnection方法。當客戶端嘗試連接到服務器的監聽端口時,incomingConnection方法被觸發。 
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();} 
全年征稿/資訊合作 聯系郵箱:1271141964@qq.com

免責聲明

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

<
更多 >

工控網機器人儀器儀表物聯網3D打印工業軟件金屬加工機械包裝機械印刷機械農業機械食品加工設備制藥設備倉儲物流環保設備造紙機械工程機械紡織機械化工設備電子加工設備水泥設備海洋水利裝備礦冶設備新能源設備服裝機械印染機械制鞋機械玻璃機械陶瓷設備橡塑設備船舶設備電子元器件電氣設備


我要投稿
  • 投稿請發送郵件至:(郵件標題請備注“投稿”)1271141964.qq.com
  • 聯系電話0571-89719789
工業4.0時代智能制造領域“互聯網+”服務平臺
智能制造網APP

功能豐富 實時交流

智能制造網小程序

訂閱獲取更多服務

微信公眾號

關注我們

抖音

智能制造網

抖音號:gkzhan

打開抖音 搜索頁掃一掃

視頻號

智能制造網

公眾號:智能制造網

打開微信掃碼關注視頻號

快手

智能制造網

快手ID:gkzhan2006

打開快手 掃一掃關注
意見反饋
關閉
企業未開通此功能
詳詢客服 : 0571-87858618
主站蜘蛛池模板: 宜城市| 五原县| 隆回县| 永嘉县| 多伦县| 鸡西市| 石楼县| 民丰县| 出国| 海淀区| 丹凤县| 石家庄市| 鄯善县| 余庆县| 石狮市| 四子王旗| 建阳市| 额济纳旗| 福海县| 岗巴县| 西林县| 长岛县| 来凤县| 临海市| 大石桥市| 津南区| 称多县| 韶关市| 那坡县| 乐亭县| 佛冈县| 句容市| 恭城| 海南省| 古交市| 阳春市| 阜宁县| 思南县| 固安县| 阳西县| 竹北市|