Qt tcp socket编程

来源:互联网 发布:iphone6网络连接不上 编辑:程序博客网 时间:2024/06/05 14:36

《学习笔记》

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设计的,这里就不再多说了,初学笔记,如果有错误的地方欢迎指正,共同进步

0 0