本项目为本科课程作业,仅供参考学习,有问题或建议欢迎与作者交流
TCP连接:Socket套接字基础知识
TCP(Transmission Control Protocol 传输控制协议)把连接作为最基本的抽象。TCP的许多特性都与TCP是面向连接的这个基本特征有关。因此我们对TCP连接需要有更清楚的了解。
每一条TCP连接有两个端点。
那么TCP连接的端点是什么呢?
TCP连接的端点不是主机的IP地址,不是应用进程,也不是运输层的协议端口。
TCP实现两个终端的通信,故除了需要获取目标主机的IP地址外,还需要目标主机的对应应用进程端口号Port,
所以TCP连接的端点叫做套接字(socket)或插口。根据RFC 793定义:端口号拼接到IP地址即构成了套接字
所以TCP使用Socket套接字作为端点。
套接字socket = (IP地址:端口号)
每一条TCP连接唯一的被通信两端的两个端点(即套接字对 socket pair)所确定。即:
TCP连接:: = { socket1,socket2 } = { (IP1, Port1), (IP2, Port2) }
这里IP1和IP2分别是两个端点主机的IP地址,而Port1和Port分别是两个端点主机中的端口号
一种理解是Socket就是该模式的一个实现:即socket是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。
TCP/IP与Socket详解参考资料
主要include一些库,定义一些函数,创建socket对象
代码如下:
#ifndef CLIENT_H
#define CLIENT_H
#include
#include
#include
#include
namespace Ui {
class Client;
}
class Client : public QMainWindow
{
Q_OBJECT
public:
explicit Client(QWidget *parent = nullptr);
~Client();
private slots:
void on_connect_button_clicked(bool checked);
void on_send_button_clicked();
void readyRead_SLOT();
void connected_SLOT();
private:
Ui::Client *ui;
QTcpSocket *socket;
};
#endif // CLIENT_H
代码如下:
#ifndef SERVER_H
#define SERVER_H
#include
#include
#include
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Server; }
QT_END_NAMESPACE
class Server : public QMainWindow
{
Q_OBJECT
public:
Server(QWidget *parent = nullptr);
~Server();
private slots:
void on_send_button_clicked();
void on_startorstop_Listen_clicked(bool checked);
void readyRead_SLOT();
void newConnection_SLOT();
private:
Ui::Server *ui;
QTcpSocket *socket;
QTcpServer *server;
};
#endif // SERVER_H
主要include一些库,定义一些函数,创建socket和server对象
#include "client.h"
#include "ui_client.h"
#include "stdio.h"
#include "QString"
Client::Client(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Client)
{
ui->setupUi(this);
//设置clicked(bool checked)点击反转状态打开
ui->connect_button->setCheckable(true);
socket = new QTcpSocket();
//信号:客户端申请连接成功 槽函数:允许写入数据
connect(socket,SIGNAL(connected()),this,SLOT(connected_SLOT()));
}
Client::~Client()
{
delete ui;
}
//信号:客户端申请连接成功 槽函数:允许写入数据
void Client::connected_SLOT()
{
connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead_SLOT()));//如果socket中有缓存消息,触发槽函数
}
//接收消息并显示到接收框
void Client::readyRead_SLOT()
{
qDebug() << "Client Received!";
QString buffer;
//读取缓冲区数据
buffer = socket->readAll();
if(!buffer.isEmpty())
{
//刷新显示
ui->receiver->appendPlainText(buffer);
}
}
//连接和断开按键
void Client::on_connect_button_clicked(bool checked)
{
if(checked)
{
QString IP = ui->ipnum->text();
int Port = ui->portnum->text().toUInt();
//取消已有的连接
socket->abort();
//连接服务器
socket->connectToHost(IP,Port);
//如果等待超过1000ms
if(!socket->waitForConnected(1000))
{
qDebug() << "Connect failed, please try again later!";
//连接失败,再次点击则重新连接,将checked恢复为true
ui->connect_button->toggle();
return;
}
qDebug() << "Connect Successfully! Connect with IP:" << IP << "; port:" << Port;
//修改按键文字
ui->connect_button->setText("断开连接");
//发送键使能
ui->send_button->setEnabled(true);
}
else
{
qDebug() << "Disconnect!";
//断开连接
socket->disconnectFromHost();
//修改按键文字&发送键静默
ui->connect_button->setText("连接");
ui->send_button->setEnabled(false);
}
}
//发送消息,写入socket缓存区
void Client::on_send_button_clicked()
{
qDebug() << "Client Send: " << ui->sender->toPlainText().toLatin1();
//将输入框的内容写入socket缓冲区
socket->write(ui->sender->toPlainText().toLatin1());
//刷新socket缓冲区
socket->flush();
}
#include "server.h"
#include "ui_server.h"
Server::Server(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::Server)
{
ui->setupUi(this);
//设置clicked(bool checked)点击反转状态打开
ui->startorstop_Listen->setCheckable(true);
socket = new QTcpSocket();
server = new QTcpServer();
//信号:新的客户端连接建立 槽函数:获取客户端套接字,允许写入数据
connect(server,SIGNAL(newConnection()),this,SLOT(newConnection_SLOT()));
}
Server::~Server()
{
delete ui;
}
//信号:新的客户端连接建立 槽函数:获取客户端套接字,允许写入数据
void Server::newConnection_SLOT()
{
socket = server->nextPendingConnection(); //获取已经连接的客户端套接字
connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead_SLOT()));//如果socket中有缓存消息,触发槽函数
}
//接收消息并显示到接收框
void Server::readyRead_SLOT()
{
qDebug() << "Server Received!";
QString buffer;
//读取缓冲区数据
buffer = socket->readAll();
if(!buffer.isEmpty())
{
//刷新显示
ui->receiver->appendPlainText(buffer);
}
}
//开始监听和停止监听按键
void Server::on_startorstop_Listen_clicked(bool checked)
{
if(checked)
{
int port = ui->portnum->text().toUInt();
//如果未监听到
if(!server->listen(QHostAddress::Any, port))
{
qDebug() << server->errorString();
//连接失败,再次点击则重新连接,将checked恢复为true
ui->startorstop_Listen->toggle();
return;
}
qDebug() << "Listen Successfully! Message from port:" << port;
//修改按钮文字
ui->startorstop_Listen->setText("停止监听");
//发送键使能
ui->send_button->setEnabled(true);
}
else
{
qDebug() << "Stop Listening!";
//如果已经连接则断开连接
if(socket->state() == QAbstractSocket::ConnectedState)
{
//断开连接
socket->disconnectFromHost();
}
//关闭倾听服务
server->close();
//修改按钮文字&发送键静默
ui->startorstop_Listen->setText("开始监听");
ui->send_button->setEnabled(false);
}
}
//发送消息,写入socket缓存区
void Server::on_send_button_clicked()
{
qDebug() << "Server Send: " << ui->sender->toPlainText().toLatin1();
//将输入框的内容写入socket缓冲区
socket->write(ui->sender->toPlainText().toLatin1());
//刷新socket缓冲区
socket->flush();
}
#include "server.h"
#include "client.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Server w1;
Client w2;
//Client窗口通过鼠标单机获得聚焦
w2.setFocusPolicy(Qt::ClickFocus);
//将客户端和服务端窗口移动到屏幕合适位置
w1.move(320,340);
w2.move(960,340);
//打开客户端和服务端窗口
w1.show();
w2.show();
return a.exec();
}
client.ui
server.ui
可以手动设计,对应文本框或窗口、按键名与代码保持一致即可。
(如果实在懒得设计想看效果,可以直接下载最下面的源码)
代码内注释很完整,有待指正,感谢阅读,您的支持是对我最大的帮助!
源代码在这