一、TCP工作原理
Tcp是面向连接的一种流式通信,能够提供可靠的通信连接,使一台客户机发出的字节流无差错地送达网络上的其他计算器。如果是对可靠性要求高的数据通信系统则需要使用Tcp传输数据,但是要发送数据,则必须首先建立连接。
二、TCP编程模型
1)首先启动服务器,成功后启动客户端;
2)客户端与服务器进行三次握手后建立连接;
3)客户端向服务端发送请求;
4)服务端发送给客户端响应;
5)多次循环,知道通讯结束,最后关闭网络连接。
三、TCP通信传输类型:
1)基于行的方式
?????基于行的数据通信协议用于一般用于纯文本数据的通信,每一行数据以换行符结束。
2)基于数据块方式
?????基于块的数据通信协议用于一般的二进制数据传输,需要自定义具体格式。
四、代码示例:
1、效果图
2、代码示例
1)TCP服务端
mainwindow.h?:
#ifndef MAINWINDOW_H #define MAINWINDOW_H
#include <QMainWindow> #include <QLabel> #include <QTcpServer> #include <QTcpSocket> #include <QAbstractSocket>
namespace Ui { class MainWindow; }
class MainWindow : public QMainWindow { ? ? Q_OBJECT
public: ? ? explicit MainWindow(QWidget *parent = 0); ? ? ~MainWindow(); ? ? QString ?getLocalIP();
private slots: ? ? void onNewConnection(); ? ? void onSocketStateChange(QAbstractSocket::SocketState); ? ? void onClientConnected(); ? ? void onClientDisconnected(); ? ? void onSocketReadyRead(); ? ? void on_connectBtn_clicked(); ? ? void on_disconnectBtn_clicked(); ? ? void on_sendBtn_clicked(); ? ? void on_clearBtn_clicked();
private: ? ? Ui::MainWindow *ui; ? ? QLabel ?*labListen; ? ? QLabel ?*labSocketState; ? ? QTcpServer ?*tcpServer; ? ? QTcpSocket ?*tcpSocket; };
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QHostInfo>
MainWindow::MainWindow(QWidget *parent) : ? ? QMainWindow(parent), ? ? ui(new Ui::MainWindow) { ? ? ui->setupUi(this); ? ? QString localIP = getLocalIP(); ? ? ui->ipLineEdit->setText(localIP); ? ? ui->portLineEdit->setText("1000");
? ? labListen = new QLabel(QString::fromLocal8Bit("监听状态:")); ? ? labListen->setMinimumWidth(150); ? ? ui->statusBar->addWidget(labListen);
? ? labSocketState = new QLabel(QString::fromLocal8Bit("Socket状态:")); ? ? labSocketState->setMinimumWidth(200); ? ? ui->statusBar->addWidget(labSocketState);
? ? tcpServer = new QTcpServer(this); ? ? connect(tcpServer, SIGNAL(newConnection()), this, SLOT(onNewConnection())); }
MainWindow::~MainWindow() { ? ? delete ui; }
QString MainWindow::getLocalIP() { ? ? QString hostName = QHostInfo::localHostName(); //主机名 ? ? QHostInfo hostInfo = QHostInfo::fromName(hostName); ? ? QString localIP = ""; ? ? QList<QHostAddress> addList = hostInfo.addresses();
? ? if(!addList.isEmpty()){ ? ? ? ? for(int i = 0; i<addList.count(); i++) ? ? ? ? { ? ? ? ? ? ? QHostAddress hostAddr = addList.at(i); ? ? ? ? ? ? if(QAbstractSocket::IPv4Protocol == hostAddr.protocol()) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? localIP = hostAddr.toString(); ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? return localIP; }
void MainWindow::onNewConnection() { ? ? tcpSocket = tcpServer->nextPendingConnection(); ? ? connect(tcpSocket, SIGNAL(connected()), this, SLOT(onClientConnected())); ? ? onClientConnected(); ? ? connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(onClientDisconnected())); ? ? connect(tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChange(QAbstractSocket::SocketState))); ? ? onSocketStateChange(tcpSocket->state()); ? ? connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(onSocketReadyRead())); }
void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState) { ? ? switch (socketState) ? ? { ? ? case QAbstractSocket::UnconnectedState: ? ? ? ? labSocketState->setText(QString::fromLocal8Bit("socket 状态: UnconnectedState")); ? ? ? ? break; ? ? case QAbstractSocket::HostLookupState: ? ? ? ? labSocketState->setText(QString::fromLocal8Bit("socket 状态: HostLookupState")); ? ? ? ? break; ? ? case QAbstractSocket::ConnectingState: ? ? ? ? labSocketState->setText(QString::fromLocal8Bit("socket 状态: ConnectingState")); ? ? ? ? break; ? ? case QAbstractSocket::ConnectedState: ? ? ? ? labSocketState->setText(QString::fromLocal8Bit("socket 状态: ConnectedState")); ? ? ? ? break; ? ? case QAbstractSocket::BoundState: ? ? ? ? labSocketState->setText(QString::fromLocal8Bit("socket 状态: BoundState")); ? ? ? ? break; ? ? case QAbstractSocket::ClosingState: ? ? ? ? labSocketState->setText(QString::fromLocal8Bit("socket 状态: ClosingState")); ? ? ? ? break; ? ? case QAbstractSocket::ListeningState: ? ? ? ? labSocketState->setText(QString::fromLocal8Bit("socket 状态: ListeningState")); ? ? ? ? break; ? ? default: ? ? ? ? break; ? ? } }
void MainWindow::onClientConnected() { ? ? ui->plainTextEdit->appendPlainText("**client socket connected"); ? ? ui->plainTextEdit->appendPlainText("**peer address:" + tcpSocket->peerAddress().toString()); ? ? ui->plainTextEdit->appendPlainText("**peer port:" + QString::number(tcpServer->serverPort())); ? ? ui->connectBtn->setEnabled(false); ? ? ui->disconnectBtn->setEnabled(true); }
void MainWindow::onClientDisconnected() { ? ? ?ui->plainTextEdit->appendPlainText("**client socket disconnected"); ? ? ?tcpSocket->deleteLater(); }
void MainWindow::onSocketReadyRead() { //一、基于行的网络传输 // ? ?while(tcpSocket->canReadLine()) // ? ? // ? ? ? ?ui->plainTextEdit->appendPlainText("[client] " + tcpSocket->readLine()); // ? ?} ? ? //二、基于块的网络传输 ? ? //1)方案一: // ? ?while(tcpSocket->bytesAvailable() > 0) // ? ?{ // ? ? ? ?ui->plainTextEdit->appendPlainText("[client] " + tcpSocket->readAll()); // ? ?} ? ? //2)方案二: ? ? while (!tcpSocket->atEnd()) ? ? { ? ? ? ? ?QByteArray data = tcpSocket->read(255); ? ? ? ? ?ui->plainTextEdit->appendPlainText("[client] " + data); ? ? } }
void MainWindow::on_connectBtn_clicked() { ? ? QString IP = ui->ipLineEdit->text(); ? ? quint16 port = ui->portLineEdit->text().toUInt();
? ? if(!tcpServer->listen(QHostAddress(IP), port)) ? ? { ? ? ? ? ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("服务器监听失败!")); ? ? } ? ? else ? ? { ? ? ? ? ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("服务器监听成功!")); ? ? ? ? ui->connectBtn->setEnabled(false); ? ? ? ? ui->disconnectBtn->setEnabled(true); ? ? ? ? labListen->setText(QString::fromLocal8Bit("监听状态,正在监听")); ? ? } }
void MainWindow::on_disconnectBtn_clicked() { ? ? if(tcpServer->isListening()) ? ? { ? ? ? ? tcpServer->close();//停止监听 ? ? ? ? ui->connectBtn->setEnabled(true); ? ? ? ? ui->disconnectBtn->setEnabled(false); ? ? ? ? labListen->setText(QString::fromLocal8Bit("监听状态:已停止监听")); ? ? } }
void MainWindow::on_sendBtn_clicked() { ? ? QString msg = ui->MsgLineEdit->text(); ? ? ui->plainTextEdit->appendPlainText("[server] " + msg); ? ? ui->MsgLineEdit->clear(); ? ? ui->MsgLineEdit->setFocus();
// ? ?QByteArray dataArray = msg.toUtf8(); // ? ?dataArray.append('\n'); // ? ?tcpSocket->write(dataArray); ? ? QByteArray dataArray = msg.toUtf8(); ? ? tcpSocket->write(dataArray); ? ? tcpSocket->flush(); }
void MainWindow::on_clearBtn_clicked() { ? ? ui->MsgLineEdit->clear(); ? ? ui->plainTextEdit->clear(); }
2)客户端
mainwindow.h:
#ifndef MAINWINDOW_H #define MAINWINDOW_H
#include <QMainWindow> #include <QTcpSocket> #include <QLabel> #include <QAbstractSocket>
namespace Ui { class MainWindow; }
class MainWindow : public QMainWindow { ? ? Q_OBJECT
public: ? ? explicit MainWindow(QWidget *parent = 0); ? ? ~MainWindow(); ? ? QString getLocalIP(); private slots: ? ? void onConnected(); ? ? void onDisconnected(); ? ? void onSocketStateChange(QAbstractSocket::SocketState); ? ? void onSocketReadyRead(); ? ? void on_connectBtn_clicked();
? ? void on_disconnectBtn_clicked();
? ? void on_sendBtn_clicked();
? ? void on_clearBtn_clicked();
private: ? ? Ui::MainWindow *ui; ? ? QTcpSocket ?*tcpClient; ? ? QLabel *labSocketState;
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QHostInfo>
MainWindow::MainWindow(QWidget *parent) : ? ? QMainWindow(parent), ? ? ui(new Ui::MainWindow) { ? ? ui->setupUi(this); ? ? this->setWindowTitle(QString::fromLocal8Bit("客户端"));
? ? QString localIP = getLocalIP(); ? ? ui->ipLineEdit->setText(localIP); ? ? ui->portLineEdit->setText("1000");
? ? labSocketState = new QLabel(QString::fromLocal8Bit("Socket状态:")); ? ? labSocketState->setMinimumWidth(250); ? ? ui->statusBar->addWidget(labSocketState); ? ? //tcpSocket ? ? tcpClient = new QTcpSocket(this);
? ? connect(tcpClient, SIGNAL(connected()), this, SLOT(onConnected())); ? ? connect(tcpClient, SIGNAL(disconnected()), this, SLOT(onDisconnected())); ? ? connect(tcpClient, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChange(QAbstractSocket::SocketState))); ? ? connect(tcpClient, SIGNAL(readyRead()), this, SLOT(onSocketReadyRead())); }
MainWindow::~MainWindow() { ? ? delete ui; }
QString MainWindow::getLocalIP() { ? ? QString hostName = QHostInfo::localHostName(); //主机名 ? ? QHostInfo hostInfo = QHostInfo::fromName(hostName); ? ? QString localIP = ""; ? ? QList<QHostAddress> addList = hostInfo.addresses();
? ? if(!addList.isEmpty()) ? ? { ? ? ? ? for(int i = 0; i<addList.count(); i++) ? ? ? ? { ? ? ? ? ? ? ?QHostAddress hostAddr = addList.at(i); ? ? ? ? ? ? ?if(QAbstractSocket::IPv4Protocol == hostAddr.protocol()) ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ?localIP = hostAddr.toString(); ? ? ? ? ? ? ? ? ?break; ? ? ? ? ? ? ?} ? ? ? ? } ? ? } ? ? return localIP; }
void MainWindow::onConnected() { ? ? ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("**已连接到服务器")); ? ? ui->plainTextEdit->appendPlainText("**peer address:" + tcpClient->peerAddress().toString()); ? ? ui->plainTextEdit->appendPlainText("**peer port:" + QString::number(tcpClient->peerPort())); ? ? ui->connectBtn->setEnabled(false); ? ? ui->disconnectBtn->setEnabled(true); }
void MainWindow::onDisconnected() { ? ? ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit("**已断开与服务器连接")); ? ? ui->connectBtn->setEnabled(true); ? ? ui->disconnectBtn->setEnabled(false); }
void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState) { ? ? switch (socketState) ? ? { ? ? case QAbstractSocket::UnconnectedState: ? ? ? ? labSocketState->setText(QString::fromLocal8Bit("socket 状态: UnconnectedState")); ? ? ? ? break; ? ? case QAbstractSocket::HostLookupState: ? ? ? ? labSocketState->setText(QString::fromLocal8Bit("socket 状态: HostLookupState")); ? ? ? ? break; ? ? case QAbstractSocket::ConnectingState: ? ? ? ? labSocketState->setText(QString::fromLocal8Bit("socket 状态: ConnectingState")); ? ? ? ? break; ? ? case QAbstractSocket::ConnectedState: ? ? ? ? labSocketState->setText(QString::fromLocal8Bit("socket 状态: ConnectedState")); ? ? ? ? break; ? ? case QAbstractSocket::BoundState: ? ? ? ? labSocketState->setText(QString::fromLocal8Bit("socket 状态: BoundState")); ? ? ? ? break; ? ? case QAbstractSocket::ClosingState: ? ? ? ? labSocketState->setText(QString::fromLocal8Bit("socket 状态: ClosingState")); ? ? ? ? break; ? ? case QAbstractSocket::ListeningState: ? ? ? ? labSocketState->setText(QString::fromLocal8Bit("socket 状态: ListeningState")); ? ? ? ? break; ? ? default: ? ? ? ? break; ? ? } }
void MainWindow::onSocketReadyRead() { ? //一、基于行的网络传输 // ? ?while(tcpClient->canReadLine()) // ? ?{ // ? ? ? ui->plainTextEdit->appendPlainText("[Server] " + tcpClient->readLine()); // ? ?} ? ? //二、基于块的网络传输 ? ? //1)方案一: // ? ?while(tcpClient->bytesAvailable() > 0) // ? ?{ // ? ? ? ?ui->plainTextEdit->appendPlainText("[Server] " + tcpClient->readAll()); // ? ?} ? ? //2)方案二: ? ? while (!tcpClient->atEnd()) ? ? { ? ? ? ? ?QByteArray data = tcpClient->read(255); ? ? ? ? ?ui->plainTextEdit->appendPlainText("[Server] " + data); ? ? } }
void MainWindow::on_connectBtn_clicked() { ? ? QString addrIP = ui->ipLineEdit->text(); ? ? quint16 port = ui->portLineEdit->text().toUInt(); ? ? tcpClient->connectToHost(addrIP, port); }
void MainWindow::on_disconnectBtn_clicked() { ? ? if(tcpClient->state() == QAbstractSocket::ConnectedState) ? ? { ? ? ? ? tcpClient->disconnectFromHost(); ? ? } }
void MainWindow::on_sendBtn_clicked() { ? ? QString msg = ui->MsgLineEdit->text(); ? ? ui->plainTextEdit->appendPlainText("[Client] " + msg); ? ? ui->MsgLineEdit->clear(); ? ? ui->MsgLineEdit->setFocus();
// ? ?QByteArray dataArray = msg.toUtf8(); // ? ?dataArray.append('\n'); // ? ?tcpClient->write(dataArray);
? ? QByteArray dataArray = msg.toUtf8(); ? ? tcpClient->write(dataArray); ? ? tcpClient->flush(); }
void MainWindow::on_clearBtn_clicked() { ? ? ui->MsgLineEdit->clear(); ? ? ui->plainTextEdit->clear(); }
|