一、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
#include
#include
#include
#include
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
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
if(!addList.isEmpty()){
for(int i = 0; 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
#include
#include
#include
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
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
if(!addList.isEmpty())
{
for(int i = 0; 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();
}