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

废话少说:直接上代码

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


这个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();  
}  



  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值