Qt tcp socket编程
2016-06-24 16:20
986 查看
《学习笔记》
QTcpSever用于监听,QTcpSocket用于连接客户端和服务端。
客户端连接服务端很简单,connectToHost(QHostAddress("IP", 666);,填写IP和端口就可以,连接成功后,再关联信号readyRead()就可以读取服务端发送过来的数据了
服务端首先监听某个端口,看是否有连接到该端口的机器,然后获取客户端连接的socket有两种方法:
1:关联信号newConnection(),在接受连接的过程中,应当是有一个队列,等待的连接都将放入连接队列中,在相应的槽函数中通过nextPendingConnection 函数可以得到该socket,进而可以进行通信,通信还是通过readyRead()信号,注意:这种方式返回的socket不可以用于另一个线程
2:另一种方法是继承QTcpSocket类重写incomingConnection (qintptr socketDescriptor) 函数
,再有连接时这个函数会被系统调用,socketDescriptor 为套接字描述符,用这个描述符创建一个socket就可以了,即setSocketDescriptor
这个函数,描述符传给这个函数参数即可。
下面是我参照网上写的测试代码,可以同时有多个客户端连接到服务的同一个端口进行相互之间通信
服务端:
chatSever.h
chatSever.cpp
tcpSocket.h
tcpSocket.cpp
chatSeverUI.h
chatSeverUI.cpp
main函数就很简单了,只是显示了各个窗口而已
界面是用QTDesign设计的,这里就不再多说了,初学笔记,如果有错误的地方欢迎指正,共同进步
QTcpSever用于监听,QTcpSocket用于连接客户端和服务端。
客户端连接服务端很简单,connectToHost(QHostAddress("IP", 666);,填写IP和端口就可以,连接成功后,再关联信号readyRead()就可以读取服务端发送过来的数据了
服务端首先监听某个端口,看是否有连接到该端口的机器,然后获取客户端连接的socket有两种方法:
1:关联信号newConnection(),在接受连接的过程中,应当是有一个队列,等待的连接都将放入连接队列中,在相应的槽函数中通过nextPendingConnection 函数可以得到该socket,进而可以进行通信,通信还是通过readyRead()信号,注意:这种方式返回的socket不可以用于另一个线程
2:另一种方法是继承QTcpSocket类重写incomingConnection (qintptr socketDescriptor) 函数
,再有连接时这个函数会被系统调用,socketDescriptor 为套接字描述符,用这个描述符创建一个socket就可以了,即setSocketDescriptor
这个函数,描述符传给这个函数参数即可。
下面是我参照网上写的测试代码,可以同时有多个客户端连接到服务的同一个端口进行相互之间通信
服务端:
chatSever.h
#include <QObject>
#include <qtcpserver.h>
#include <QList>
#include <tcpsocket.h>
class chatSever : public QTcpServer
{
Q_OBJECT
public:
explicit chatSever(QObject *parent = 0, int port = 0);
//重载
void incomingConnection(int handle);
void sendMsgToClient(QString strMsg, int nLength);
private:
QList<tcpSocket*> m_clientSocketLst; //用于保存客户端链表
signals:
public slots:
void updateClientsData(QString msg, int length);
void slotDisconnected(int descriptor);
};
chatSever.cpp
#include "chatsever.h"
chatSever::chatSever(QObject *parent, int port) : QTcpServer(parent)
{
//监听
listen(QHostAddress::Any, port);
}
void chatSever::incomingConnection(int handle)
{
tcpSocket* clientSocket = new tcpSocket(this);
clientSocket->setSocketDescriptor(handle);
m_clientSocketLst.append(clientSocket);
connect(clientSocket, SIGNAL(updateClientsData(QString,int)), this, SLOT(updateClientsData(QString,int)));
//一个socket断开连接就从底层链表中删除对应的对象
connect(clientSocket, SIGNAL(disconed(int)), this, SLOT(slotDisconnected(int)));
}
void chatSever::sendMsgToClient(QString strMsg, int nLength)
{
updateClientsData(strMsg, nLength);
}
void chatSever::updateClientsData(QString msg, int length)
{
for(int i = 0; i < m_clientSocketLst.count(); ++i)
{
QTcpSocket* itemClient = m_clientSocketLst.at(i);
if(itemClient->write(msg.toLatin1().data(), length) != length)
{
qDebug() << "存在数据丢失";
continue;
}
}
}
//删除指定的socket对象
void chatSever::slotDisconnected(int descriptor)
{
qDebug() << "slotDisconnected";
for(int i = 0; i < m_clientSocketLst.count(); ++i)
{
QTcpSocket* item = m_clientSocketLst.at(i);
if(item->socketDescriptor() == descriptor)
{
m_clientSocketLst.removeAt(i);
qDebug() << QString("socket列表 = : %1").arg(m_clientSocketLst.count());
return;
}
}
}
tcpSocket.h
#include <QObject>
#include <QTcpSocket>
class tcpSocket : public QTcpSocket
{
Q_OBJECT
public:
explicit tcpSocket(QObject *parent = 0);
signals:
void updateClientsData(QString, int);
void disconed(int);
public slots:
void dataRecived();
void slotDisconnected();
};
tcpSocket.cpp
#include "tcpsocket.h"
tcpSocket::tcpSocket(QObject *parent) : QTcpSocket(parent)
{
//建立处理客户端的槽函数
connect(this, SIGNAL(readyRead()), this, SLOT(dataRecived()));
connect(this, SIGNAL(disconnected()), this, SLOT(slotDisconnected()));
}
//读取客户端信息
void tcpSocket::dataRecived()
{
while (bytesAvailable() > 0) {//貌似解决了发送方粘包的问题,加上还是好
char buf[1024] = {0};
int nLength = bytesAvailable(); //返回可用字节数
read(buf, nLength);
QString str = buf;
emit updateClientsData(str, nLength);
}
}
void tcpSocket::slotDisconnected()
{
qDebug() << "slotDisconnected";
emit disconed(socketDescriptor());
}
chatSeverUI.h
#include <QWidget>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QTcpServer>
#include "chatsever.h"
namespace Ui {
class socketSever;
}
class chatSeverUI : public QWidget
{
Q_OBJECT
public:
explicit chatSeverUI(QWidget *parent = 0);
~chatSeverUI();
void initSocket();
public slots:
// void acceptConnection();
// void readClient();
private slots:
void on_pushButton_clicked();
private:
Ui::socketSever *ui;
QTcpServer* m_sever;
QTcpSocket* m_clientConet;
chatSever* m_chatSever;
};
chatSeverUI.cpp
#include "chatseverUI.h"
#include "ui_socketsever.h"
#include <QtNetwork/qhostaddress.h>
chatSeverUI::chatSeverUI(QWidget *parent) :
QWidget(parent),
ui(new Ui::socketSever)
{
ui->setupUi(this);
m_sever = NULL;
m_clientConet = NULL;
m_chatSever = NULL;
initSocket();
}
chatSeverUI::~chatSeverUI()
{
delete ui;
}
void chatSeverUI::initSocket()
{
/*
* 方法1
m_sever = new QTcpServer(this);
m_sever->listen(QHostAddress::Any, 6666);
connect(m_sever, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
*/
//方法2
m_chatSever = new chatSever(this, 6666);
if(!m_chatSever->isListening())
{
qDebug() << QString("unable to start the sever : %1").arg(m_chatSever->errorString());
}
}
/*
void chatSeverUI::acceptConnection()
{
m_clientConet = m_sever->nextPendingConnection();
connect(m_clientConet, SIGNAL(readyRead()), this, SLOT(readClient()));
}
void chatSeverUI::readClient()
{
QString str = m_clientConet->readAll();
ui->severLabel->setText(str);
}
*/
void chatSeverUI::on_pushButton_clicked()
{
QString str = ui->severEdit->text();
//m_clientConet->write(str.toLatin1().data());
m_chatSever->sendMsgToClient(str.toLatin1().data(), str.length());
}
main函数就很简单了,只是显示了各个窗口而已
chatClientUI client1;
client1.setWindowTitle("client");
client1.show();
chatClientUI client2;
client2.setWindowTitle("client");
client2.show();
chatClientUI client3;
client3.setWindowTitle("client");
client3.show();
chatSeverUI sever;
sever.setWindowTitle("sever");
sever.show();
界面是用QTDesign设计的,这里就不再多说了,初学笔记,如果有错误的地方欢迎指正,共同进步
相关文章推荐
- QTP 依次读取文本中的各行数据
- QTP 数据库连接字符串动态赋值
- qtp执行文本中的sql语句/脚本
- Qt资料大全
- Qt资料大全
- MQTT 客户端应用及常见问题(C#)
- MQTT客户端搭建及应用(Nodejs)
- http://emqtt.com/
- Qt获取本机IP地址和名称
- QT QTreeWidget 选中某行并设置背景色高亮
- QTcrateor 编译 ROS
- Qt5实现串口通信
- 使用QProcess调用另一个程序
- qt5集成libcurl实现tftp和ftp的方法一:搭建环境(五篇文章)
- Qt中的信号和槽
- Qt之QImageReader
- Qt之QImageReader
- Qt之QImageWriter
- Qt之QImageWriter
- [Q学习]14 Qt状态机框架——进入和退出状态3