QT_TCP下的socket编程

上传人:cl****1 文档编号:571422411 上传时间:2024-08-10 格式:PDF 页数:9 大小:88.57KB
返回 下载 相关 举报
QT_TCP下的socket编程_第1页
第1页 / 共9页
QT_TCP下的socket编程_第2页
第2页 / 共9页
QT_TCP下的socket编程_第3页
第3页 / 共9页
QT_TCP下的socket编程_第4页
第4页 / 共9页
QT_TCP下的socket编程_第5页
第5页 / 共9页
点击查看更多>>
资源描述

《QT_TCP下的socket编程》由会员分享,可在线阅读,更多相关《QT_TCP下的socket编程(9页珍藏版)》请在金锄头文库上搜索。

1、QT TCP 下的 socket 编程转载:http:/ 转载 2011-03-01 17:06:41 阅读8 评论0 字号:大中小 订阅QTcpSocket 和 QTcpServer 类实现了Qt的Tcp 客户端和服务器。tcp 是一个流式协议。对于应用程序来说,数据是一个很长的流,有点像一个巨 大的文件。搞成此的协议建立在面向块的tcp 协议(Block-oriented)或面向行(Line-oriented )的tcp 协议上。面向块的tcp 协议,数据被当作一个2 进制的块来传输。没每一个块被当作一个 定义了大小的,后面跟随了数据的字段。面向行的tcp 协议,数据被当作一个文本文件的一

2、行。一个传输终止于一个新的 行的到来。QTcpSocket 继承自 QIODevice ,所以它可以从 QDataStream 或 QTextStream 中读取或写入数据。 “从文件读数据和从网络上读数据有一个明显的不同点: 我们必须保证用 ” 操作符读取数据时 ,已经从另一方接收了足够的数据。 如果你这样做了,那么一 个失败的结果是:行为未定义。我们来看一个使用block-oriented tcp 协议的服务器和客户端的代码。用户填写行程的起始地,目的地,日期等,服务器返回符合要求的行程。界面用QDesigner“设计的。叫做 tripplanner.ui”。请使用uic 工具转换。inc

3、lude ui_tripplanner.hclass TripPlanner : public QDialog, public Ui:TripPlanner Q_OBJECTpublic: TripPlanner(QWidget *parent = 0);private slots: void connectToServer(); void sendRequest(); void updateTableWidget(); void stopSearch(); void connectionClosedByServer(); void error();private: void closeCon

4、nection(); QTcpSocket tcpSocket; /tcpSocket 变量是QTcpSocket 类型,用来建立一个tcp 连接。 quint16 nextBlockSize; /当需要提起从服务器传递来的数据块时,nextBlockSize 将被使用。;TripPlanner:TripPlanner(QWidget *parent) : QDialog(parent) setupUi(this); QDateTime dateTime = QDateTime:currentDateTime(); /取当前时间 dateEdit-setDate(dateTime.date()

5、;/将当前日期设置到相应控件中 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(cl

6、icked(),this, SLOT(connectToServer();/search 单击时,连接服务器 connect(stopButton, SIGNAL(clicked(), this, SLOT(stopSearch();/stop 停止连接服务器 connect(&tcpSocket, SIGNAL(connected(), this, SLOT(sendRequest();/如果连接好则发送返回信息? connect(&tcpSocket, SIGNAL(disconnected(),this, SLOT(connectionClosedByServer();/若没连接好,则关

7、闭连接 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 TripP

8、lanner: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 ()槽将被执行。 它使

9、用tcpSocket.connectToHost 建立到服务器的连接。 connectToServer()槽立即返回。 连接的动作实际发生在这之后。当连接建立成功,QTcpSocket 触发connected() 信号。如果失败,error()信号被触发。接着我们设置进度条以及按钮的状态。把nextBlockSize 设置为0.表示我们现在并不知道下一个接收的数据块的大小。 void TripPlanner:sendRequest() QByteArray block; QDataStream out(&block, QIODevice:WriteOnly); out.setVersion(Q

10、DataStream:Qt_4_1); out quint16(0) quint8(S) currentText() currentText() date() time(); if (departureRadioButton-isChecked() out quint8(D); else out seek(0); out setText(tr(Sending request.);当connected()信号被触发,sendRequest()槽被调用。sendRequest()向服务器发送一个请求(tcpSocket.write(block))。 我们需要在数据块的第一个字段写入数据块的大小。但

11、是当我们些第一个字段时,我们不知道整个数据块的大小,所以我们现写入0(out seek(0)),重新写入数据块的大小out rowCount(); if (nextBlockSize = 0) if (tcpSocket.bytesAvailable() nextBlockSize; if (nextBlockSize = 0xFFFF) closeConnection(); statusLabel-setText(tr(Found %1 trip(s).arg(row); break; if (tcpSocket.bytesAvailable() date departureTime dur

12、ation 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

13、(changes) trainType; for (int i = 0; i setItem(row, i, new QTableWidgetItem(fieldsi); nextBlockSize = 0; 当QTcpSocket 接收到数据时,readyRead()信号被触发 。updateTableWidget() 槽 就被调用了。这里我们用了一个forever 循环,这是必须的!因为我们无法保证一次就接到了所有的数据块。可能,我们只接收到数据块的一个部分,也可能是全部。 forever 循环是如何工作的呢?如果nextBlockSize 是0,表示我们没有独到 数据块的大小,我们必须重

14、新读取它。 数据块的大小字段必须至少读取sizeof(quint16)字节才能获得,如果读取的数据少于sizeof(quint16),必须重新读取。如果数据块大小字段为0xFFFF ,表示服务器端数据发送完毕,我们停止接收。 最后我们设置nextBlockSize 为0,表示下一个数据块的大小还不知道,我们必须接收。 void TripPlanner:closeConnection() tcpSocket.close(); searchButton-setEnabled(true); stopButton-setEnabled(false); progressBar-hide();当接收到的数

15、据块大小字段的值为 0xFFFF,我们关闭连接。 void TripPlanner:stopSearch() statusLabel-setText(tr(Search stopped); closeConnection();如果stopServer 按钮被单击,我们关闭连接。 void TripPlanner:connectionClosedByServer() if (nextBlockSize != 0xFFFF) statusLabel-setText(tr(Error: Connection closed by server); closeConnection(); 当服务器断开连接

16、时,如果我们没有读到表示数据传送完毕的 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(); 接下来,我们看看服务器端的实现。class TripServer : publi

17、c 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-setSocketDescri

18、ptor(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(QO

19、bject *parent)ut quint16(0) ). 最后,当数据块填充完毕时,我们计算数据块的大小,将指针重新 : QTcpSocket(parent) connect(this, SIGNAL(readyRead(), this, SLOT(readClient(); connect(this, SIGNAL(disconnected(), this, SLOT(deleteLater(); nextBlockSize = 0; void ClientSocket:readClient() QDataStream in(this); in.setVersion(QDataStrea

20、m:Qt_4_1); if (nextBlockSize = 0) if (bytesAvailable() nextBlockSize; if (bytesAvailable() 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)ut quint16(0) ). 最后,当数据块填充完毕时

21、,我们计算数据块的大小,将指针重新 generateRandomTrip(from, to, date, time); QDataStream out(this); out quint16(0xFFFF); close();void ClientSocket:generateRandomTrip(const QString & /* from */, const QString & /* to */, const QDate &date, const QTime &time) QByteArray block; QDataStream out(&block, QIODevice:WriteOn

22、ly); out.setVersion(QDataStream:Qt_4_1); quint16 duration = rand() % 200; out quint16(0) date time duration quint8(1) 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();

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 建筑/环境 > 施工组织

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号