QT += network
#include
#include
#include
tcp客户端只需要QTcpSocket。
tcp服务端,需要QTcpServer 来监听,QTcpSocket来管理客户端连接
udp需要QUdpSocket
打开
QTcpSocket m_handle;
//连接信号槽,接收消息
QObject::connect(&m_handle, &QTcpSocket::readyRead, this, &XXX::slotReadyRead);
// 连接断开响应
QObject::connect(&m_handle, &QTcpSocket::disconnected, this, &XXX::slotDisconnected);
//套接字错误响应
QObject::connect(&m_handle, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(slotError(QAbstractSocket::SocketError)));
//连接服务器
m_handle.connectToHost(IP, PORT);
//等待连接成功
if(!m_handle.waitForConnected(1000))
{
qDebug() << "Connection failed!";
}
qDebug() << "Connect successfully!";
关闭
m_handle.disconnectFromHost();
QObject::disconnect(&m_handle, 0, 0, 0);
发送
QByteArray sendData;
qint64 written = m_handle.write(sendData);
m_handle.flush();
接收槽函数
void XXX::slotReadyRead()
{
QByteArray buffer = m_handle.readAll();
qDebug() << buffer;
// ……
}
断开槽函数
void XXX::slotDisconnected()
{
//取消已有的连接
m_handle.abort();
qDebug() << "Disconnected!";
}
出错槽函数
void XXX::slotError(QAbstractSocket::SocketError)
{
//取消已有的连接
m_handle.abort();
}
比客户端多了 客户端监听 以及 已连接客户端的维护
启动监听
QTcpServer m_server;
if (m_server.listen(QHostAddress::Any, port)) {
// 连接信号槽,当有新的客户端连接时响应
QObject::connect(&m_server, &QTcpServer::signal_incomingConnection, this, &XXX::slot_incomingConnection);
qDebug() << "Server listenning!";
}
else {
qDebug() << m_server.errorString();
}
客户端连接槽函数
QList m_list;
void XXX::slot_incomingConnection() //响应客户端连接请求的函数
{
//获取连接的客户端
QTcpSocket *client = tcpServer.nextPendingConnection();
m_list.append(client );
//连接信号槽,用于接收客户端消息
connect(client , SIGNAL(readyRead()), this, SLOT(slot_readyRead()));
}
客户端接收槽函数,可以发现无法直接知道是哪个客户端发来的消息
void xxx::slot_readyRead()
{
// 遍历所有客户端,检查谁有待读取的消息
for (int i = 0; i < m_list.size(); i++)
{
if (m_list.at(i)->bytesAvailable())
{
//读取消息并保存
QByteArray buffer = m_list.at(i)->readAll();
qDebug() << buffer;
}
}
}
发送
void XXX::send(int i, const QByteArray &buf)
{
m_list.at(i)->write(buf);
}
维护客户端连接情况
// 当前连接数
unsigned int size = m_list.size();
//删除断开的客户端
for (unsigned int i = 0; i < size ; i++)
{
// 判断当前客户端是否未连接
if (m_list.at(i)->state() == QAbstractSocket::UnconnectedState)
{
m_list.removeAt(i);
--i;
--size ;
}
}
由于正常的使用qtcpsocket,当接收到消息或者当断开连接时无法知道是哪个客户端发起的。为了解决这个问题,可以自QTcpSocket派生子类。
qtcpserver类的正常使用,需nextPendingConnection获取新连接的客户端,这个在多个客户端同时发起时可能存在问题。也可以自QTcpServer派生子类来解决。
具体操作是
1、在qtcpserver派生类中增加一个信号(包含描述符和套接字),并在incomingConnection重载函数中emit。
2、在qtcpsocket派生类中改写信号(增加描述符和套接字),绑定原始信号(readyRead、disconnected等),在槽函数中emit改写的信号。
由于信号都带上了描述符和socket,绑定的槽函数直接就能知道发起的客户端描述符和套接字。
udp比较简单,绑定端口,就可以收发了。
打开
QUdpSocket m_handle;
m_handle.bind(port,QUdpSocket::ShareAddress);
// 绑定槽函数,接收消息
connect(&m_handle,&QUdpSocket::readyRead,this,&XXX::slot_readyRead);
qDebug() << "Bind successfully!";
发送
QByteArray sendData;
qint64 written = m_handle.writeDatagram(sendData.data(),
sendData.size(),
QHostAddress(ip),
port);
m_handle.flush();
接收槽函数
void XXX::slot_readyRead()
{
QByteArray buffer;
//有未处理的消息
if(m_handle.hasPendingDatagrams()){
buffer.resize(m_handle.pendingDatagramSize());
m_handle.readDatagram(buffer.data(),buffer.size());
qDebug() << buffer;
//……
}
}