一:TCP通信介绍
.TCP是面向连接的可靠传输的协议,协议规定交换的双方必须是服务端和客户端的两个角色:
--- 服务端负责监听网络端口,等待客户端的连接,用连接的socket完成信息的交互;
--- 客户端负责每次连接的发起,建立连接后才可以进行通信;
.TCP的连接是基于流的,数据按照正确的顺序存储在接收缓冲区中,它保证数据能正确的进行交换,但不能保证数据以发送端的数据帧的形式提交。
二:界面设计
客户端
服务端
三:客户端编码
客户端编码步骤如下:
(1)创建QTcpSocket套接字对象
socket = new QTcpSocket();
(2)使用这个对象连接服务器
//连接服务器
socket->connectToHost(IP,port);
(3)使用write函数向服务器发送数据
//获取文本框的数据并以ASCII码发送出去
void MainWindow::on_pushButton_Send_clicked()
{
socket->write(ui->textEdit_Send->toPlainText().toLatin1());
socket->flush();
}
(4)当socket接收缓冲区有新数据到来时,会发出readyRead()信号,因此为该信号添加槽函数以读取数据。
//构造函数中连接
QObject::connect(socket,&QTcpSocket::readyRead,this,&MainWindow::socket_Read_Data);
void MainWindow::socket_Read_Data()
{
QByteArray buffer;
//读取数据缓冲区数据
buffer = socket->readAll();
}
(5)断开与服务器的连接
//断开连接
socket->disconnectFromHost();
四:服务端编码
服务端编码步骤如下:
(1)创建QTcpServer对象
server = new QTcpServer();
(2)侦听一个端口,使得客户端可以使用这个端口访问服务器
//监听指定的端口
if(!server->listen(QHostAddress::Any,port)){
qDebug()<errorString();
}
(3)当服务器被访问时,会发出newConnection()信号,所以为该信号添加槽函数,并用一个QTcpSocket对象接受客户端的访问
//构造函数中连接
connect(server,&QTcpServer::newConnection,this,&MainWindow::server_New_Connection);
void MainWindow::server_New_Connection()
{
//获取客户端的连接
socket = server->nextPendingConnection();
}
(4)使用socket的write函数向客户端发送数据
//客户端有新连接是发送信号
QObject::connect(socket,&QTcpSocket::readyRead,this,&MainWindow::socket_Read_Data);
void MainWindow::socket_Read_Data()
{
QByteArray buffer;
//读取数据缓冲中的数据
buffer = socket->readAll();
}
(5)当socket接受缓冲区有新数据到来时,会发出readyRead()信号,为该信号添加槽函数
//获取文本框数据并且以ASCII码的形式发送
void MainWindow::on_pushButton_Send_clicked()
{
socket->write(ui->textEdit_Send->toPlainText().toLatin1());
socket->flush();
}
(6)取消侦听
server->close();
五:修改*.pro文件
在文件中添加网络应用的代码库network
QT += core gui network
六:中文乱码处理
上述发送接收的代码都是单字节数据,对于发送中文数据,在发送和接收是需要做如下处理:
发送数据:
void MainWindow::on_pushButton_Send_clicked()
{
qDebug()<<"Send: "<textEdit_Send->toPlainText();
//兼容中文数据发送
socket->write(ui->textEdit_Send->toPlainText().toLocal8Bit());
socket->flush();
//获取文本框数据并且以ASCII码的形式发送
//socket->write(ui->textEdit_Send->toPlainText().toLatin1());
//socket->flush();
}
socket->write(ui->textEdit_Send->toPlainText().toLocal8Bit());
socket->flush();
//获取文本框数据并且以ASCII码的形式发送
//socket->write(ui->textEdit_Send->toPlainText().toLatin1());
//socket->flush();
}
接收数据:
void MainWindow::socket_Read_Data()
{
QByteArray buffer;
//读取数据缓冲区数据
buffer = socket->readAll();
if(!buffer.isEmpty()){
QString str = ui->textEdit_Recv->toPlainText();
QString strRecv = QString::fromLocal8Bit(buffer);
str+=strRecv+"\n";
//刷新显示
ui->textEdit_Recv->setText(str);
}
}
QString strRecv = QString::fromLocal8Bit(buffer);
str+=strRecv+"\n";
//刷新显示
ui->textEdit_Recv->setText(str);
}
}
七:细节注意
(1)Qt5 抛弃了QTextCodec::setCodecForTr()和QTextCodec::setCodecForCString()这两个函数。
直接将 QTextCodec::setCodecForLocale(QTextCodec::codecForName(“UTF8”)) 至于QApplication实例之前即可解决;
(2)本示例中,newConnection信号是对于单线程适用的,nextPendingConnection()只能用于当前线程中,当服务端面向多连接服务时,需要重载incomingConnection()方法,用socket描述符socketDescriptor定义连接socket
代码连接地址:https://pan.baidu.com/s/1eSELrnO 提取码:2ym3
欢迎进群,一起探讨NB的代码