码迷,mamicode.com
首页 > 其他好文 > 详细

对Qt下对话服务器客户端的总结(MyTcpServer与MyTcpClient)

时间:2015-07-23 19:12:11      阅读:406      评论:0      收藏:0      [点我收藏+]

标签:

Qt编写聊天服务器与客户端主要用到下面两个类:

  • QTcpSocket --- 处理连接的
  • QTcpServer --- 处理服务器,对接入进行响应,创建每个链接的QTcpSocket实例

编写网络程序需要在 .pro 文件中加上 network,如下

QT       += core gui network

 


 

1.客户端的编写

客户端需要做的事:

  • 获取服务器的主机ip和端口(port)
  • 链接主机(connectToHost)
  • 链接状态下等待一些信号(signal)的产生并作出相应的回应(slot)

主要等待的信号由一下几个:

void connected()
void disconnected()
void error(QAbstractSocket::SocketError socketError)
void readyRead()

并为这几个信号写相应的槽函数对该情况作出处理

 

以下为我的具体实现代码:

我的ui界面是这样的:

技术分享

技术分享
 1 #ifndef TCPCLIENT_H
 2 #define TCPCLIENT_H
 3 
 4 #include <QWidget>
 5 #include <QMessageBox>
 6 #include <QTcpSocket>
 7 #include <QDebug>
 8 #include <QHostAddress>
 9 #include <QTextStream>
10 
11 namespace Ui {
12 class TcpClient;
13 }
14 
15 class TcpClient : public QWidget
16 {
17     Q_OBJECT
18 
19 public:
20     explicit TcpClient(QWidget *parent = 0);
21     ~TcpClient();
22 
23 private slots:
24     void on_connectPushButton_clicked();    //connect按键槽函数
25     
26     void slotConnect();  
27     void slotErr(QAbstractSocket::SocketError err);
28     void slotDisconnect();
29     void slotReadData();
30 
31     void on_sendPushButton_clicked();     //send按键槽函数
32     void on_sendLineEdit_returnPressed();    //sendLineEdit的回车槽
33 
34 private:
35     Ui::TcpClient *ui;    
36     QTcpSocket *socket;   //客户端的文件描述符
37     bool isConnect;      //connect按键的状态变换值
38 };
39 
40 #endif // TCPCLIENT_H
tcpclient.h
技术分享
  1 #include "tcpclient.h"
  2 #include "ui_tcpclient.h"
  3 
  4 TcpClient::TcpClient(QWidget *parent) :
  5     QWidget(parent),
  6     ui(new Ui::TcpClient)
  7 {
  8     ui->setupUi(this);
  9     isConnect = true;
 10 }
 11 
 12 TcpClient::~TcpClient()
 13 {
 14     delete ui;
 15 }
 16 
 17 void TcpClient::on_connectPushButton_clicked()
 18 {
 19     QString hostip;
 20     quint16 port;
 21     if(isConnect)
 22     {
 23         /*判断ip和端口是否填写,并获取该ip和端口*/
 24         if(ui->ipLineEdit->text().isEmpty())
 25         {
 26             QMessageBox::information(this,"ip","The ip is empty,please input a ip");
 27             return ;
 28         }
 29         hostip = ui->ipLineEdit->text();
 30         if(ui->portLineEdit->text().isEmpty())
 31         {
 32             QMessageBox::information(this,"port","The port is empty,please input a port");
 33             return ;
 34         }
 35         port = ui->portLineEdit->text().toShort();
 36 
 37         /*连接服务器,并在这之前连接几个必要的信号*/
 38         socket = new QTcpSocket;
 39         //已连接信号
 40         connect(socket,SIGNAL(connected()),this,SLOT(slotConnect()));
 41         //连接出现错误信号
 42         connect(socket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(slotErr(QAbstractSocket::SocketError)));
 43         //连接断开信号
 44         connect(socket,SIGNAL(disconnected()),this,SLOT(slotDisconnect()));
 45         //准备读取数据信号
 46         connect(socket,SIGNAL(readyRead()),this,SLOT(slotReadData()));
 47         socket->connectToHost(QHostAddress(hostip),port);
 48     }
 49     else
 50     {
 51         socket->disconnectFromHost();
 52         ui->connectPushButton->setText("connect");
 53         isConnect = true;
 54     }
 55 }
 56 
 57 //槽函数定义
 58 void TcpClient::slotConnect()
 59 {
 60     QMessageBox::information(this,"connect","host connect sucess");
 61     ui->ipLineEdit->setEnabled(false);
 62     ui->portLineEdit->setEnabled(false);
 63     ui->connectPushButton->setText("disconnect");
 64     isConnect = false;
 65 }
 66 
 67 void TcpClient::slotErr(QAbstractSocket::SocketError err)
 68 {
 69     qDebug("error is %d",err);
 70     ui->connectPushButton->setText("connect");
 71 }
 72 
 73 void TcpClient::slotDisconnect()
 74 {
 75     QMessageBox::information(this,"disconnect","host disconnect sucess");
 76     ui->ipLineEdit->setEnabled(true);
 77     ui->portLineEdit->setEnabled(true);
 78     ui->connectPushButton->setText("connect");
 79     isConnect = true;
 80 }
 81 
 82 void TcpClient::slotReadData()
 83 {
 84     qDebug()<<"have data";
 85     if(socket->bytesAvailable()>0)
 86     {
 87         QString msg;
 88         QByteArray ba;
 89         ba.resize(socket->bytesAvailable());
 90         socket->read(ba.data(),ba.size());
 91         msg = QString(ba);
 92 
 93 //        QTextStream out(socket);
 94 //        QString msg;
 95 //        out >> msg;
 96         ui->msgListWidget->addItem(msg);
 97     }
 98 }
 99 
100 
101 void TcpClient::on_sendPushButton_clicked()
102 {
103     QTextStream in(socket);
104     in << ui->sendLineEdit->text();
105     ui->sendLineEdit->clear();
106 }
107 
108 
109 void TcpClient::on_sendLineEdit_returnPressed()
110 {
111     QTextStream in(socket);
112     in << ui->sendLineEdit->text();
113     ui->sendLineEdit->clear();
114 }
tcpcilent.cpp
技术分享
#include "tcpclient.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TcpClient w;
    w.show();

    return a.exec();
}
main.cpp

 

总结:客户端的编写比较容易,只要连接服务器,发送信息给服务器就可以

 


 

2.服务器的编写

服务器需要做的事:

  • Qt对于服务器有专门的类 QTcpServer封装,所以不需要去自己配置服务器(socket,bind),可以直接侦听(listen)
  • 当有客户端连接的时候分配文件描述符和地址标示客户端
  • 然后等待客户端发送信息(这里会得到一些信号,通过信号来处理),接收信号,转发(发送给链接在服务器的其他人)或者回馈信息。
  • 服务器需要支持多客户端,所以要有保存和删除客户端信息的处理。

因为需要实现支持多客户端接入的服务器,所以需要将显示层(ui),服务器层,socket层分开。可以看下面这个图来理解

技术分享

简述下这里的流程,首先,客户端发送请求,服务器分配(创建)一个socket,然后incomingConnection()函数捕捉到这个socket,并在此响应客户端(接收消息,转发消息)。然后在这里创建一个信息转发消息到ui界面

通过这样的模型,我们就可以创建一个多客户端的服务器。

 

 

接下来的一张图我来解释下我的程序中信号与槽函数之间连接的关系(人类总是对视觉的感官来的更直接点)

技术分享

结合上面的图和我的代码就很清晰的能看出信号与槽在这三层之间的传递关系

下面是的我的代码区

技术分享
 1 #ifndef MYTCPSOCKET_H
 2 #define MYTCPSOCKET_H
 3 
 4 #include <QObject>
 5 #include <QTcpSocket>
 6 #include <QTextStream>
 7 #include <QHostAddress>
 8 
 9 
10 class MyTcpSocket : public QTcpSocket
11 {
12     Q_OBJECT
13 public:
14 
15     MyTcpSocket();
16     ~MyTcpSocket();
17 
18 signals:
19     void disconnectSignal(qintptr);
20     void sockReadDataSignal(qintptr,QString);
21 
22 private slots:
23     void readDataSlot();
24     void disconnectSlot();
25 };
26 
27 #endif // MYTCPSOCKET_H
mytcpsocket.h
技术分享
 1 #include "mytcpsocket.h"
 2 
 3 MyTcpSocket::MyTcpSocket()
 4 {
 5     QObject::connect(this,SIGNAL(readyRead()),this,SLOT(readDataSlot()));
 6     QObject::connect(this,SIGNAL(disconnected()),this,SLOT(disconnectSlot()));
 7 }
 8 
 9 MyTcpSocket::~MyTcpSocket()
10 {
11 
12 }
13 
14 void MyTcpSocket::readDataSlot()
15 {
16     //读取数据的两种方式
17     qDebug()<<"read data";
18     QString msg;
19     QByteArray ba;
20     ba.resize(this->bytesAvailable());
21     this->read(ba.data(),ba.size());
22     msg = QString(ba);
23     qDebug()<<"ip:"<<this->peerAddress().toString();
24 
25 //    QTextStream out(this),in(this);
26 //    QString msg;
27 //    out >> msg;
28     emit sockReadDataSignal(this->socketDescriptor(),msg);
29 }
30 
31 void MyTcpSocket::disconnectSlot()
32 {
33     qDebug()<<"disconnect";
34     emit disconnectSignal(this->socketDescriptor());
35 }
mytcpsocket.cpp
技术分享
 1 #ifndef MYTCPSERVER_H
 2 #define MYTCPSERVER_H
 3 
 4 #include <QObject>
 5 #include <QHostAddress>
 6 #include <QTcpServer>
 7 #include <QDebug>
 8 #include <QList>
 9 #include "mytcpsocket.h"
10 
11 class MyTcpServer : public QTcpServer
12 {
13    Q_OBJECT
14 public:
15     MyTcpServer();
16     ~MyTcpServer();
17 
18 protected:
19     void incomingConnection(qintptr socketDescriptor);
20 
21 
22 private slots:
23     void disconnectSlot(qintptr);
24     void answerMsgSlot(qintptr,QString);
25 
26 signals:
27     void serverReadDataSignal(qintptr,QString);
28 
29 private:
30     QList<MyTcpSocket *> clients;
31 
32 };
33 
34 #endif // MYTCPSERVER_H
mytcpserver.h
技术分享
 1 #include "mytcpserver.h"
 2 
 3 MyTcpServer::MyTcpServer()
 4 {
 5     listen(QHostAddress::Any,8080);
 6 }
 7 
 8 MyTcpServer::~MyTcpServer()
 9 {
10 
11 }
12 
13 void MyTcpServer::incomingConnection(qintptr socketDescriptor)//when a new connection is available.
14 {
15     qDebug()<<"connect success";
16     MyTcpSocket  *sock = new MyTcpSocket;
17     sock->setSocketDescriptor(socketDescriptor);
18     QObject::connect(sock,SIGNAL(disconnectSignal(qintptr)),this,SLOT(disconnectSlot(qintptr)));
19     QObject::connect(sock,SIGNAL(sockReadDataSignal(qintptr,QString)),this,SIGNAL(serverReadDataSignal(qintptr,QString)));
20     QObject::connect(sock,SIGNAL(sockReadDataSignal(qintptr,QString)),this,SLOT(answerMsgSlot(qintptr,QString)));
21     clients << sock;
22 }
23 
24 
25 void MyTcpServer::disconnectSlot(qintptr sockfd)
26 {
27 //    MyTcpSocket *sock = new MyTcpSocket;
28 //    sock->setSocketDescriptor(socketDescriptor);
29     qDebug()<<"delete client "<<sockfd;
30     for (int i = 0; i < clients.size(); ++i)
31     {
32         if (clients.at(i)->socketDescriptor() == sockfd)
33             clients.removeAt(i);
34     }
35 
36    // delete sock;
37 }
38 
39 void MyTcpServer::answerMsgSlot(qintptr sockfd, QString msg)
40 {
41     for (int i = 0; i < clients.size(); ++i)
42     {
43         if(clients.at(i)->socketDescriptor() != sockfd)
44         {
45             QTextStream in(clients.at(i));
46             in << sockfd << ":" << msg << endl;
47         }
48     }
49 }
mytcpserver.cpp
技术分享
 1 #ifndef MYTCPSERVERWIDGET_H
 2 #define MYTCPSERVERWIDGET_H
 3 
 4 #include <QWidget>
 5 #include "mytcpserver.h"
 6 #include <QObject>
 7 
 8 namespace Ui {
 9 class MyTcpServerWidget;
10 }
11 
12 class MyTcpServerWidget : public QWidget
13 {
14     Q_OBJECT
15 
16 public:
17     explicit MyTcpServerWidget(QWidget *parent = 0);
18     ~MyTcpServerWidget();
19 
20 private slots:
21     void widgetReadDataSlot(qintptr,QString);
22 
23 private:
24     Ui::MyTcpServerWidget *ui;
25     MyTcpServer *tcpserver;
26 };
27 
28 #endif // MYTCPSERVERWIDGET_H
mytcpserverwidget.h
技术分享
 1 #include "mytcpserverwidget.h"
 2 #include "ui_mytcpserverwidget.h"
 3 
 4 MyTcpServerWidget::MyTcpServerWidget(QWidget *parent) :
 5     QWidget(parent),
 6     ui(new Ui::MyTcpServerWidget)
 7 {
 8     ui->setupUi(this);
 9     tcpserver = new MyTcpServer; //connect to the server
10     QObject::connect(tcpserver,SIGNAL(serverReadDataSignal(qintptr,QString)),this,SLOT(widgetReadDataSlot(qintptr,QString)));
11 
12 }
13 
14 MyTcpServerWidget::~MyTcpServerWidget()
15 {
16     delete ui;
17 }
18 
19 
20 void MyTcpServerWidget::widgetReadDataSlot(qintptr sock, QString msg)
21 {
22     QString id;
23     id = QString::number(sock);
24     ui->listWidget->addItem(id+":"+msg);
25 }
mytcpserverwidget.cpp
技术分享
 1 #include "mytcpserverwidget.h"
 2 #include <QApplication>
 3 
 4 int main(int argc, char *argv[])
 5 {
 6     QApplication a(argc, argv);
 7     MyTcpServerWidget w;
 8     w.show();
 9 
10     return a.exec();
11 }
main.cpp

 

最后附带一个写的很好的blog

Qt浅谈之十六:TCP和UDP(之一)

 

对Qt下对话服务器客户端的总结(MyTcpServer与MyTcpClient)

标签:

原文地址:http://www.cnblogs.com/panhao/p/4670999.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!