TCP協議概述
主要特點
1.TCP是面向連接的運輸層協議。應用和曾許在使用TCP協議之前,必須首先建立TCP連接。在傳輸數據完畢之后,必須將已經建立好的TCP給釋放。也就是說,應用進程之間的通信好像在“打電話”:通話之前首先要撥通號碼建立連接,通話結束之后必須掛掉電話釋放連接。
2.每一條TCP連接只能有兩個端點,每一條TCP連接只能是點對點的。
3.TCP提供的是可靠交付的服務。通過TCP連接傳送的數據,無差錯,不丟失,不重復,按照順序到達。
4.TCP提供全雙工通信。TCP允許通信雙方的應用進程在任何時候都能夠發送數據。TCP連接的兩端都設置了發送緩沖和接收緩沖區用來臨時存放雙向通信的數據。在發送時候,應用程序把數據傳送給TCP的緩存之后,就可以去干自己的事情了,TCP會在合適的時候把數據發送出去。在接收的時候,TCP會把收到的數據放入緩存,上層應用進程在合適的時候會讀取緩沖區的數據。
5.面向字節流。
TCP的連接
TCP把連接作為最基本的抽象。TCP的許多特性都和TCP是面向連接的這個基本特性有關。
前面已經講過,每一條TCP連接有兩個端點。那么,TCP連接的端點是什么呢》
他叫做套接字(Socket),具體的定義為:端口拼接到IP地址即構成套接字。因此套接字的表示方法是在點分十進制的IP地址后面寫上端口號,中間使用冒號或者逗號隔開。例如,若IP地址是192.168.3.4 而端口號是50,那么得到的套接字就是(192.168.3.4:50)。
套接字Socket = IP地址:端口號
每一條TCP連接唯一地被通訊兩端的兩個套接字所確定。
TCP的編程模型
程序編寫的流程圖如圖所示。

首先是啟動服務器,一段時間之后啟動客戶端,它與此服務器經過三次握手后建立連接。在此后的一段時間內,客戶端向服務器發送一個強求,服務器處理這個請求,並為客戶端發回一個響應。這個過程會一直持續下去,直到客戶端為服務器發送一個文件結束符,並關閉客戶端的連接,接着服務器也會關閉服務器端的連接,結束運行或者等待一個新的客戶端加入。
在QT中使用QTcpSocket類和QTcpServer類實現TCP協議的編程。
基於QT的實現
首先在項目文件中添加 QT += core gui network CONFIG += C++11 ,編譯不運行(點擊小錘子)
服務器的實現:
severwidget.h
#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H
#include <QWidget>
#include <QTcpServer> //監聽套接字
#include <QTcpSocket> //通信套接字
namespace Ui {
class ServerWidget;
}
class ServerWidget : public QWidget
{
Q_OBJECT
public:
explicit ServerWidget(QWidget *parent = 0);
~ServerWidget();
private slots:
void on_ButtonSend_clicked();
void on_ButtonClose_clicked();
private:
Ui::ServerWidget *ui;
QTcpServer *tcpServer; //定義監聽套接字tcpServer
QTcpSocket *tcpSocket; //定義通信套接字tcpSocket
};
#endif // SERVERWIDGET_H
main.cpp
#include "serverwidget.h"
#include <QApplication>
#include"clientwidget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ServerWidget w;
w.show();
ClientWidget w2;
w2.show();
return a.exec();
}
severwidget.cpp
#include "serverwidget.h"
#include "ui_serverwidget.h"
ServerWidget::ServerWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ServerWidget)
{
ui->setupUi(this);
//監聽套接字,指定父對象,讓其自動回收空間
tcpServer = new QTcpServer(this);
setWindowTitle("服務器:6666");
tcpServer->listen(QHostAddress::Any,6666);
connect(tcpServer,&QTcpServer::newConnection,
[=]()
{
//取出建立好連接的套接字
tcpSocket = tcpServer->nextPendingConnection();
//獲取對方的IP和端口
QString ip = tcpSocket->peerAddress().toString();
qint16 port = tcpSocket->peerPort();
QString temp = QString("[%1:%2]:成功連接").arg(ip).arg(port);
ui->textEditRead->setText(temp);
//接收
connect(tcpSocket,&QTcpSocket::readyRead,
[=]()
{
//從通訊套接字中取出內容
QByteArray array = tcpSocket->readAll();
//使用settext可以將以前的進行覆蓋,使用append會在后面添加
ui->textEditRead->append(array);
}
);
}
);
}
ServerWidget::~ServerWidget()
{
delete ui;
}
void ServerWidget::on_ButtonSend_clicked()
{
if(NULL == tcpSocket)
{
return;
}
//獲取編輯區內容
QString str = ui->textEditWrite->toPlainText();
//給對方發送數據,使用套接字是tcpSocket
tcpSocket->write( str.toUtf8().data());
}
void ServerWidget::on_ButtonClose_clicked()
{
if(NULL == tcpSocket)
{
return;
}
//主動和客戶端斷開連接
tcpSocket->disconnectFromHost();
tcpSocket->close();
tcpSocket == NULL;
}
ui:

客戶端的實現
clientwidget.h
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H
#include <QWidget>
#include <QTcpSocket>//通信套接字
namespace Ui {
class ClientWidget;
}
class ClientWidget : public QWidget
{
Q_OBJECT
public:
explicit ClientWidget(QWidget *parent = 0);
~ClientWidget();
private slots:
void on_ButtonConnect_clicked();
void on_ButtonSend_clicked();
void on_ButtonClose_clicked();
private:
Ui::ClientWidget *ui;
QTcpSocket *tcpSocket;
};
#endif // CLIENTWIDGET_H
clientwidget.cpp
#include "clientwidget.h"
#include "ui_clientwidget.h"
#include<QHostAddress>
ClientWidget::ClientWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ClientWidget)
{
ui->setupUi(this);
tcpSocket = NULL;
// tcpServer = NULL;
//分配空間,指定父對象
tcpSocket = new QTcpSocket(this);
connect(tcpSocket, &QTcpSocket::connected,
[=]()
{
ui->textEditRead->setText("成功和服務器建立連接");
}
);
//接收數據
connect(tcpSocket,&QTcpSocket::readyRead,
[=]()
{
//獲取對方發送的內容
QByteArray arry = tcpSocket->readAll();
//顯示在編輯區
ui->textEditRead->append(arry);
}
);
}
ClientWidget::~ClientWidget()
{
delete ui;
}
void ClientWidget::on_ButtonConnect_clicked()
{
//獲取服務器IP和端口
QString ip = ui->lineIP->text();
qint16 port = ui->linePort->text().toInt();
//主動和服務器建立連接
tcpSocket->connectToHost(QHostAddress(ip),port);
}
void ClientWidget::on_ButtonSend_clicked()
{
//獲取編輯框內容
QString str = ui->textEditWrite->toPlainText();
//發送數據
tcpSocket->write(str.toUtf8().data());
}
void ClientWidget::on_ButtonClose_clicked()
{
//主動和對方斷開連接
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
ui

實現效果

下載地址:
