废话少说:直接上代码
代码功能:客户端先向服务发送一个字符串,服务器收到后,再向客户端发送一个同样的字符串(回射字符串)
这个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();
}