四、Socket通信#

c++的socket通信非常麻烦,并且在不同的平台上实现是不同的

Qt的socket可以实现跨平台

Qt中Socket通信的类:

  • QTcpServer

用于TCP/IP通信,作为服务器端套接字使用

  • QTcpScoket

用于TCP/IP通信,作为客户端套接字使用

  • QUdpSocket

用于UDP通信,服务端和客户端均使用此套接字

1. tcp通信#

1.服务端需要监听一个端口

2.客户端需要连接上服务端才能通信

1、客户端ClientWindow.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
ClientWindow::ClientWindow(QWidget* parent):QWidget(parent) {
    //创建QTCPSocket指针对象
    socket = new QTcpSocket(this);
    //设置大小
    setFixedSize(600,600);
    //设置标题
    setWindowTitle("客户端");
    //创建布局
    QVBoxLayout *layout = new QVBoxLayout;
    QHBoxLayout *hl = new QHBoxLayout;
    QFormLayout*fl = new QFormLayout;

    QLineEdit*ipEdit = new QLineEdit;
    QLineEdit*portEdit = new QLineEdit;
    ipEdit->setText("127.0.0.1");
    portEdit->setText("6666");

    QPushButton*connectBtn = new QPushButton("连接");

    fl->addRow("服务器 ip:",ipEdit);
    fl->addRow("服务器端口:",portEdit);
    hl->addLayout(fl);
    hl->addWidget(connectBtn);


    QTextEdit *recvMsg = new QTextEdit;
    QTextEdit *sendMsg = new QTextEdit;

    recvMsg->setEnabled(false);

    QHBoxLayout *btnLayout = new QHBoxLayout;
    QPushButton*sendBtn = new QPushButton("发送");
    QPushButton*closeBtn = new QPushButton("关闭");

    layout->addLayout(hl);
    layout->addWidget(recvMsg);
    layout->addWidget(sendMsg);
    btnLayout->addWidget(sendBtn);
    btnLayout->addWidget(closeBtn);
    layout->addLayout(btnLayout);

    setLayout(layout);

    //信号和槽函数
    connect(connectBtn,&QPushButton::clicked,[=](){
        //获取ip和顿口
        QString ip = ipEdit->text();
        quint16 port = portEdit->text().toInt();
        socket->connectToHost(ip,port);
    });
    connect(sendBtn,&QPushButton::clicked,[=](){
        QString msg = sendMsg->toPlainText();
        socket->write(msg.toUtf8().data());
    });
    //接收到新消息
    connect(socket,&QTcpSocket::readyRead,this,[=](){
        QByteArray data = socket->readAll();
        recvMsg->append(QString(data));
    });
}

2、服务端ServerWindow.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
ServerWindow::ServerWindow(QWidget *parent) : QWidget(parent) {
    //设置大小
    setFixedSize(600, 600);
    //设置标题
    setWindowTitle("服务器:6666");
    //创建布局
    QVBoxLayout *layout = new QVBoxLayout;
    recvMsg = new QTextEdit;
    sendMsg = new QTextEdit;

    recvMsg->setEnabled(false);

    QHBoxLayout *btnLayout = new QHBoxLayout;
    QPushButton *sendBtn = new QPushButton("发送");
    QPushButton *closeBtn = new QPushButton("关闭");

    layout->addWidget(recvMsg);
    layout->addWidget(sendMsg);
    btnLayout->addWidget(sendBtn);
    btnLayout->addWidget(closeBtn);
    layout->addLayout(btnLayout);

    setLayout(layout);

    //初始化socket
    initSocket();

    connect(sendBtn,&QPushButton::clicked,[=](){
        QString msg = sendMsg->toPlainText();
        socket->write(msg.toUtf8().data());
    });
}

ServerWindow::~ServerWindow() {

}

//初始化socket
void ServerWindow::initSocket() {
    //创建socket
    server = new QTcpServer(this);
    //监听
    server->listen(QHostAddress::Any, 6666);
    //连接上的信号和槽函数
    connect(server, &QTcpServer::newConnection, this, &ServerWindow::clientConnectToServer);
}

//连接上的信号和槽函数
void ServerWindow::clientConnectToServer() {
    //保存通信套接字
    socket = server->nextPendingConnection();
    //获取连接的ip和端口
    QString ip = socket->peerAddress().toString();
    int port = socket->peerPort();
    //写入
    recvMsg->append(QString("[%1:%2]连接成功").arg(ip).arg(port));
    //监听新消息
    connect(socket,&QTcpSocket::readyRead,this,&ServerWindow::receiveMsg);
}

//有新消息
void ServerWindow::receiveMsg(){
    QByteArray data = socket->readAll();
    recvMsg->append(QString(data));
}

2. udp通信#

udp通信不需要连接服务端操作

1、客户端ClientWindow.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
ClientWindow::ClientWindow(QWidget *parent) : QWidget(parent) {
    socket = new QUdpSocket(this);
    //设置大小
    setFixedSize(600, 600);
    //设置标题
    setWindowTitle("客户端:8888");
    //创建布局
    QVBoxLayout *layout = new QVBoxLayout;
    QHBoxLayout *hl = new QHBoxLayout;
    QFormLayout *fl = new QFormLayout;

    QLineEdit *ipEdit = new QLineEdit;
    QLineEdit *portEdit = new QLineEdit;
    ipEdit->setText("127.0.0.1");
    portEdit->setText("6666");

    QPushButton *connectBtn = new QPushButton("连接");

    fl->addRow("服务器 ip:", ipEdit);
    fl->addRow("服务器端口:", portEdit);
    hl->addLayout(fl);
    hl->addWidget(connectBtn);

    QTextEdit *recvMsg = new QTextEdit;
    QTextEdit *sendMsg = new QTextEdit;

    recvMsg->setEnabled(false);

    QHBoxLayout *btnLayout = new QHBoxLayout;
    QPushButton *sendBtn = new QPushButton("发送");
    QPushButton *closeBtn = new QPushButton("关闭");

    layout->addLayout(hl);
    layout->addWidget(recvMsg);
    layout->addWidget(sendMsg);
    btnLayout->addWidget(sendBtn);
    btnLayout->addWidget(closeBtn);
    layout->addLayout(btnLayout);

    setLayout(layout);

    socket->bind(8888, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);

    connect(sendBtn, &QPushButton::clicked, [=]() {
        QString ip = ipEdit->text();
        int port = portEdit->text().toInt();
        QString msg = sendMsg->toPlainText();

        socket->writeDatagram(msg.toUtf8(),QHostAddress(ip),port);
    });
}

2、服务端ServerWindow.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
ServerWindow::ServerWindow(QWidget *parent) : QWidget(parent) {
    socket = new QUdpSocket(this);
    //设置大小
    setFixedSize(600, 600);
    //设置标题
    setWindowTitle("客户端:6666");
    //创建布局
    QVBoxLayout *layout = new QVBoxLayout;
    QHBoxLayout *hl = new QHBoxLayout;
    QFormLayout *fl = new QFormLayout;

    QLineEdit *ipEdit = new QLineEdit;
    QLineEdit *portEdit = new QLineEdit;
    ipEdit->setText("127.0.0.1");
    portEdit->setText("8888");

    QPushButton *connectBtn = new QPushButton("连接");

    fl->addRow("服务器 ip:", ipEdit);
    fl->addRow("服务器端口:", portEdit);
    hl->addLayout(fl);
    hl->addWidget(connectBtn);


    QTextEdit *recvMsg = new QTextEdit;
    QTextEdit *sendMsg = new QTextEdit;

    recvMsg->setEnabled(false);

    QHBoxLayout *btnLayout = new QHBoxLayout;
    QPushButton *sendBtn = new QPushButton("发送");
    QPushButton *closeBtn = new QPushButton("关闭");

    layout->addLayout(hl);
    layout->addWidget(recvMsg);
    layout->addWidget(sendMsg);
    btnLayout->addWidget(sendBtn);
    btnLayout->addWidget(closeBtn);
    layout->addLayout(btnLayout);

    setLayout(layout);

    socket->bind(6666, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
    connect(socket, &QUdpSocket::readyRead, [=]() {
//        QString msg = socket->readAll();
        QByteArray data;
        data.resize(socket->pendingDatagramSize());
        socket->readDatagram(data.data(), data.size());
        qDebug() << "接收到消息" << data << endl;
        socket->close();
    });
}