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
实现效果
下载地址: