QT:Qsocket长连接的实现(单线程服务器)

来源:互联网 发布:淘宝如何入驻全球购 编辑:程序博客网 时间:2024/04/27 15:11

废话少说:直接上代码

代码功能:客户端先向服务发送一个字符串,服务器收到后,再向客户端发送一个同样的字符串(回射字符串)


这个DEMO的服务器端已经在2012-2-14大幅度更新了,之前的程序存在有严重的问题(内存泄露,不释放端口。。。),
我也是新手,请大家见谅,如果大家发现这个DEMO还有什么问题,欢迎留言和建议。大家共同学习。


源代码:

//服务器端  //server.h  #ifndef CHATSERVER_H    #define CHATSERVER_H    #include <QtGui>  #include <QtNetwork>  #include <QtCore>  class ConnectSocket : public QTcpSocket    {    Q_OBJECT    public:    ConnectSocket(QObject* parent=0);    ~ConnectSocket();  void SetDescriptor(int des) { m_Descriptor = des; }signals:   void disconnectedSignal(int);    private slots:    void readMessage();  void sendMessage();  void disconnectSlot();private:  //网络断开后,描述符会立即变成-1,所以要先保存一下int m_Descriptor;QString m_String;  quint16 m_BlockSize;  };  class Server : public QTcpServer    {    Q_OBJECT    public:    Server(QObject *parent = 0,int port=0); protected:    void incomingConnection(int socketDescriptor);    private:    QMap<int, ConnectSocket*> m_ClientDesMap;public slots:     void clientDisconnected(int);    };      class Dialog : public QDialog    {    Q_OBJECT    public:    Dialog(QWidget *parent = 0);    private:    QLabel *statusLabel;    QPushButton *quitButton;    Server *server;    };    #endif // CHATSERVER_H   //server.cpp  #include "server.h"    Server::Server(QObject *parent,int port)    : QTcpServer(parent)    {   if( !listen(QHostAddress::Any,port) )  {  QMessageBox::about(NULL, "Error", "Can't connected");  exit(2);  }  }    void Server::incomingConnection(int descriptor)    {    ConnectSocket *socket = new ConnectSocket(this);    connect(socket, SIGNAL(disconnectedSignal(int)),  this, SLOT(clientDisconnected(int)));     socket->setSocketDescriptor(descriptor);//CommectSocket*一定要保存,否则连接会自动断开 m_ClientDesMap[descriptor] = socket;qDebug() << descriptor << " added";socket->SetDescriptor(descriptor);}void Server::clientDisconnected(int descriptor)    {   //连接结束一定要删除对应的socket,否则会造成内存泄漏。m_ClientDesMap[descriptor]->deleteLater();m_ClientDesMap.remove(descriptor);qDebug() << descriptor << " removed";}  Dialog::Dialog(QWidget *parent)    :QDialog(parent)    {    statusLabel = new QLabel;    quitButton = new QPushButton(tr("Quit"));    quitButton->setAutoDefault(false);    server=new Server(this,8888);    if (!server->isListening())   {    QMessageBox::critical(this, tr("Chat Server"),    tr("Unable to start the server: %1.")    .arg(server->errorString()));    close();    return;    }    QString ipAddress;    QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();    for (int i = 0; i < ipAddressesList.size(); ++i)   {    if (ipAddressesList.at(i) != QHostAddress::LocalHost &&    ipAddressesList.at(i).toIPv4Address())   {    ipAddress = ipAddressesList.at(i).toString();    break;    }    }    if (ipAddress.isEmpty())    ipAddress = QHostAddress(QHostAddress::LocalHost).toString();    statusLabel->setText(tr("The server is running on\n\nIP: %1\nport: %2\n\n"    "Run the Fortune Client example now.")    .arg(ipAddress).arg(server->serverPort()));    connect(quitButton,SIGNAL(clicked()),this,SLOT(close()));    QHBoxLayout *buttonLayout = new QHBoxLayout;    buttonLayout->addStretch(1);    buttonLayout->addWidget(quitButton);    buttonLayout->addStretch(1);    QVBoxLayout *mainLayout = new QVBoxLayout;    mainLayout->addWidget(statusLabel);    mainLayout->addLayout(buttonLayout);    setLayout(mainLayout);    setWindowTitle(tr("Chat Server"));    }    ConnectSocket::ConnectSocket(QObject* parent)    {    m_BlockSize = 0;  connect(this,SIGNAL(readyRead()),this,SLOT(readMessage()));    connect(this,SIGNAL(disconnected()),this,SLOT(disconnectSlot()));  qDebug() << this << " created";}    ConnectSocket::~ConnectSocket()    {    qDebug() << this << " deleted";}    void ConnectSocket::readMessage()  {  QDataStream in(this);  in.setVersion(QDataStream::Qt_4_0);  if (m_BlockSize == 0)  {  if (bytesAvailable() < (int)sizeof(quint16))  return;  in >> m_BlockSize;  }  if (bytesAvailable() < m_BlockSize)  return;  in >> m_String;  m_BlockSize = 0;  sendMessage();  }  void ConnectSocket::sendMessage()  {  QByteArray block;  QDataStream out(&block, QIODevice::WriteOnly);  out.setVersion(QDataStream::Qt_4_0);  out << (quint16)0;  out << m_String;  out.device()->seek(0);  out << (quint16)(block.size() - sizeof(quint16));  write(block);  }  void ConnectSocket::disconnectSlot(){emit disconnectedSignal(m_Descriptor);}//main.cpp  #include "server.h"  #include <QtGui/QApplication>  int main(int argc, char *argv[])  {  QApplication a(argc, argv);  Dialog w;  w.show();  return a.exec();  }  //客户端  //client.h  #ifndef TRYCLI_H_  #define TRYCLI_H_    #include <QtNetwork>  #include <QtGui>  #include <QtCore>    class Client : public QWidget  {      Q_OBJECT  private:      bool isConnected;      QLineEdit *serverIpEdit;      QLabel *label;      QLineEdit *strEdit;      QPushButton *startButton;        QTcpSocket *tcpClient;      quint16 blockSize;      QString sendString;      QString readString;    public:      Client();      ~Client();        public slots:          void displayError(QAbstractSocket::SocketError socketError);          void newConnect();          void readMessage();          void sendMessage();    };    #endif      //client.cpp  #include "client.h"  #include <QtGui/QMessageBox>  #include <QtGui/QHBoxLayout>  #include <QtEvents>    Client::Client()  {      setWindowTitle("Client");      resize(300, 100);        serverIpEdit = new QLineEdit("127.0.0.1");      startButton = new QPushButton("start");      strEdit = new QLineEdit;      label = new QLabel("Emtpy");      isConnected = false;        QVBoxLayout *layout = new QVBoxLayout;      layout->addWidget(serverIpEdit);      layout->addWidget(label);      layout->addWidget(strEdit);      layout->addWidget(startButton);      setLayout(layout);        tcpClient = new QTcpSocket(this);      connect(startButton, SIGNAL(clicked()), this, SLOT(newConnect()));      connect(tcpClient, SIGNAL(connected()), this, SLOT(sendMessage()));      connect(tcpClient, SIGNAL(readyRead()), this, SLOT(readMessage()));      connect(tcpClient, SIGNAL(error(QAbstractSocket::SocketError)),          this, SLOT(displayError(QAbstractSocket::SocketError)));  }    Client::~Client()  {    }    void Client::newConnect()  {      blockSize = 0;      if(!isConnected)      {          tcpClient->abort();          tcpClient->connectToHost(serverIpEdit->text(), 8888);          isConnected = true;      }      else          sendMessage();  }    void Client::sendMessage()  {      QByteArray block;      QDataStream out(&block, QIODevice::WriteOnly);      out.setVersion(QDataStream::Qt_4_0);        sendString = strEdit->text();      out << (quint16)0;      out << sendString;      out.device()->seek(0);      out << (quint16)(block.size() - sizeof(quint16));        tcpClient->write(block);  }    void Client::readMessage()  {      QDataStream in(tcpClient);      in.setVersion(QDataStream::Qt_4_0);        if (blockSize == 0)      {          if (tcpClient->bytesAvailable() < (int)sizeof(quint16))              return;          in >> blockSize;      }      if (tcpClient->bytesAvailable() < blockSize)          return;        in >> readString;      label->setText(readString);  }    void Client::displayError(QAbstractSocket::SocketError socketError)  {      switch (socketError) {      case QAbstractSocket::RemoteHostClosedError:          break;      case QAbstractSocket::HostNotFoundError:          QMessageBox::information(this, tr("Fortune Client"),              tr("The host was not found. Please check the "              "host name and port settings."));          break;      case QAbstractSocket::ConnectionRefusedError:          QMessageBox::information(this, tr("Fortune Client"),              tr("The connection was refused by the peer. "              "Make sure the fortune server is running, "              "and check that the host name and port "              "settings are correct."));          break;      default:          QMessageBox::information(this, tr("Fortune Client"),              tr("The following error occurred: %1.")              .arg(tcpClient->errorString()));      }  }      //main.cpp  #include "client.h"  #include <QtGui/QApplication>    int main(int argc, char *argv[])  {      QApplication a(argc, argv);      Client w;      w.show();      return a.exec();  }