Qt学习之路七——TCP/IP网络编程_技术小白的博客-CSDN博客
在qt中的网络编程和之前在windows中的网络编程的基本步骤是一样的,服务器有两个套接字,一个负责监听(QTcpServer),还有一个负责通信(QTcpSocket),客户端只有一个负责通信的套接字(QTcpSocket)。
添加:
QT += network
添加:
#include "QTcpSocket"
#include "QTcpServer"
1、QTcpServer对象负责监听是否有客户端连接此服务器。它是通过这样一个函数监听的
tcpserver->listen(QHostAddress::Any, 8888);
它的第一个参数表示服务器监听的地址,如果后面是Any表示监听本机的所有网口的,第二个参数表示监听的网络端口。
2、如果服务器监听到有客户端和它进行连接,服务器就会触发newConnection这个信号。同时客户端一旦和服务器连接成功,客户端会触发connected这个信号,表示已经成功和服务器连接。
3、在两者建立好连接之后,服务器需要返回一个QTcpSocket对象来和客户端进行通信,通常通过这个函数来返回一个建立好连接的套接字。
tcpsocket = tcpserver->nextPendingConnection();
4、接着就可以通过两这的通信套接字来完成通信。当一端发送成功之后,接收方会触发这么一个信号,readyRead,这样我们就能够读取套接字当中的内容了。
5、断开连接的时候我们使用这样的函数
tcpsocket->disconnectFromHost();
现在我们就通过Qt Creator来实现客户端和服务器进行通信。
一、客户端编程
1) 初始化QTcpSocket
在构造函数中,我们需要先对其进行实例化,并连接信号与槽函数:
//初始化TCP客户端
tcpClient = new QTcpSocket(this); //实例化tcpClient
tcpClient->abort(); //取消原有连接
connect(tcpClient, SIGNAL(readyRead()), this, SLOT(ReadData()));
connect(tcpClient, SIGNAL(error(QAbstractSocket::SocketError)), \
this, SLOT(ReadError(QAbstractSocket::SocketError)));
2)建立连接 和 断开连接
tcpClient->connectToHost(ui->edtIP->text(), ui->edtPort->text().toInt());
if (tcpClient->waitForConnected(1000)) // 连接成功则进入if{}
{
ui->btnConnect->setText("断开");
ui->btnSend->setEnabled(true);
}
3)读取服务器发送过来的数据
readyRead()是QTcpSocket从父类QIODevice中继承下来的信号:This signal is emitted once every time new data is available for reading from the device’s current read channel。
readyRead()对应的槽函数为:
void MyTcpClient::ReadData()
{
QByteArray buffer = tcpClient->readAll();
if(!buffer.isEmpty())
{
ui->edtRecv->append(buffer);
}
}
4)向服务器发送数据
QString data = ui->edtSend->toPlainText();
if(data != "")
{
tcpClient->write(data.toLatin1()); //qt5去除了.toAscii()
}
至此,通过4步,我们就完成了TCP Client的程序开发
二:服务器端编程
服务器段编程相比于客户端要繁琐一些,因为对于客户端来说,只能连接一个服务器。而对于服务器来说,它是面向多连接的,如何协调处理多客户端连接就显得尤为重要。
前言:编程过程中遇到的问题 和 解决的方法
遇到的问题:每个新加入的客户端,服务器给其分配一个SocketDescriptor后,就会emit newConnection()信号,但分配好的SocketDecriptor并没有通过newConnection()信号传递,所以用户得不到这个客户端标识SocketDescriptor。同样的,每当服务器收到新的消息时,客户端会emit readReady()信号,然而readReady()信号也没有传递SocketDescriptor, 这样的话,服务器端即使接收到消息,也不知道这个消息是从哪个客户端发出的。
解决的方法:
1. 通过重写[virtual protected] void QTcpServer::incomingConnection(qintptr socketDescriptor),获取soketDescriptor。自定义TcpClient类继承QTcpSocket,并将获得的soketDescriptor作为类成员。 这个方法的优点是:可以获取到soketDescriptor,灵活性高。缺点是:需要重写函数、自定义类。
2. 在newConnection()信号对应的槽函数中,通过QTcpSocket *QTcpServer::nextPendingConnection()函数获取 新连接的客户端:Returns the next pending connection as a connected QTcpSocket object. 虽然仍然得不到soketDescriptor,但可以通过QTcpSocket类的peerAddress()和peerPort()成员函数获取客户端的IP和端口号,同样是唯一标识。 优点:无需重写函数和自定义类,代码简洁。缺点:无法获得SocketDecriptor,灵活性差。