Linux与网络通信:基于TCP的网络聊天室

来源:互联网 发布:注册表编辑器删除软件 编辑:程序博客网 时间:2024/05/22 12:00

网络聊天室的功能,现在我通过Qt提供的QTcpServer和QTcpSocket实现。

TCP是一种可靠的,面向连接,面向数据流的传输协议,适用于高层协议,其中高层协议包括HTTP,FTP,而TCP协议非常适合数据的连续传输。

聊天室分为服务器端和客户端,服务器程序可以创建一个聊天室,而客户端程序可以输入登入的用户名,服务器地址以及所使用的端口号码,然后进入聊天室,在聊天室中的每个用户都可以看到聊天记录。

接下来实现的是客户端的实现:

客户端:

main.cpp

#include<QApplication>#include"tcpclient.h"int main(int argc,char *argv[]){QApplication app(argc,argv);QTranslator translator(0);translator.load("tcpclient_wxj");app.installTranslator(&translator);TcpClient *tcpclient = new TcpClient();tcpclient->show();return app.exec();}

tcpclient.h

#ifndef TCPCLIENT_H#define TCPCLIENT_H#include<QtGui>#include<QtNetwork>class TcpClient:public QDialog{Q_OBJECTpublic:TcpClient(QWidget *parent=0,Qt::WindowFlags f=0);~TcpClient();public:QListWidget *ListWidgetContent;QLineEdit *LineEditSend;QPushButton *PushButtonSend;QLabel *LabelUser;QLineEdit *LineEditUser;QLabel *LabelServerIP;QLineEdit *LineEditServerIP;QLabel *LabelPort;QLineEdit *LineEditPort;QPushButton *PushButtonEnter;QString userName;int port;QHostAddress *serverIP;QTcpSocket *tcpSocket;bool status;public slots:void slotEnter();void slotConnected();void slotDisconnected();void slotSend();void dataReceived();};#endif

tcpclient.cpp

#include"tcpclient.h"TcpClient::TcpClient(QWidget *parent,Qt::WindowFlags f):QDialog(parent,f){QFont font("ZYSong18030",12);setFont(font);setWindowTitle(tr("TCP CLient"));QVBoxLayout *vbMain = new QVBoxLayout(this); //这行开始是客户端的显示与控制ListWidgetContent = new QListWidget(this);vbMain->addWidget(ListWidgetContent);QHBoxLayout *hb1 = new QHBoxLayout();LineEditSend = new QLineEdit(this);hb1->addWidget(LineEditSend);PushButtonSend = new QPushButton(this);PushButtonSend->setText(tr("Send"));hb1->addWidget(PushButtonSend);vbMain->addLayout(hb1);QHBoxLayout *hb2 = new QHBoxLayout();LabelUser = new QLabel(this);LabelUser->setText(tr("User name:"));hb2->addWidget(LabelUser);LineEditUser = new QLineEdit(this);hb2->addWidget(LineEditUser);QHBoxLayout *hb3 = new QHBoxLayout();LabelServerIP = new QLabel(this);LabelServerIP->setText(tr("Server"));hb3->addWidget(LabelServerIP);LineEditServerIP = new QLineEdit(this);hb3->addWidget(LineEditServerIP);QHBoxLayout *hb4 = new QHBoxLayout();LabelPort = new QLabel(this);LabelPort->setText(tr("Port"));hb4->addWidget(LabelPort);LineEditPort = new QLineEdit(this);hb4->addWidget(LineEditPort);vbMain->addLayout(hb2);vbMain->addLayout(hb3);vbMain->addLayout(hb4);PushButtonEnter = new QPushButton(this);PushButtonEnter->setText(tr("Enter"));vbMain->addWidget(PushButtonEnter);connect(PushButtonEnter,SIGNAL(clicked()),this,SLOT(slotEnter()));connect(PushButtonSend,SIGNAL(clicked()),this,SLOT(slotSend()));serverIP = new QHostAddress();port = 8010;LineEditPort->setText(QString::number(port));status = false;PushButtonSend->setEnabled(false);}TcpClient::~TcpClient(){}void TcpClient::slotEnter(){if(!status)//statue表示当前状态,true表示已经进入聊天室,false表示离开聊天室{QString ip = LineEditServerIP->text();if(!serverIP->setAddress(ip))//判断给定的IP地址能否被正确解析{QMessageBox::information(this,tr("error"),tr("server ip address error"));return;}if(LineEditUser->text()==""){QMessageBox::information(this,tr("error"),tr("User name error"));return;}userName = LineEditUser->text();tcpSocket = new QTcpSocket(this);//创建QTcpSocket类对象,并将信号与槽连接connect(tcpSocket,SIGNAL(connected()),this,SLOT(slotConnected()));connect(tcpSocket,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(dataReceived()));tcpSocket->connectToHost(*serverIP,port);//与Tcp服务器连接,成功后发出connected()信号status = true;//复位}else{int length = 0;QString msg = userName+tr(":Leave chat room");//离开字符存入msgif((length=tcpSocket->write(msg.toLatin1(),msg.length()))!=msg.length()){return;}tcpSocket->disconnectFromHost();//与Tcp服务器连接,发送离开信息status = false;}}void TcpClient::slotConnected()//此函数为connected()信号的相应槽,当与服务器连接成功后,{//客户端构造一条进入聊天室的消息,并通知服务器。int length = 0;PushButtonSend->setEnabled(true);PushButtonEnter->setText(tr("Leaver"));//改变按钮状态QString msg = userName+tr(":Enter chat room");if((length=tcpSocket->write(msg.toLatin1(),msg.length()))!=msg.length()){return;}}void TcpClient::slotDisconnected(){PushButtonSend->setEnabled(false);PushButtonEnter->setText(tr("Enter"));}void TcpClient::slotSend()//发送数据,写入套接字{if(LineEditSend->text()==""){return;}QString msg = userName+":"+LineEditSend->text();tcpSocket->write(msg.toLatin1(),msg.length());LineEditSend->clear();}void TcpClient::dataReceived()//有数据到来时候触发此函数,从套接字中将有效数据取出,并显示{while(tcpSocket->bytesAvailable()>0){QByteArray datagram;datagram.resize(tcpSocket->bytesAvailable());QHostAddress sender;tcpSocket->read(datagram.data(),datagram.size());QString msg = datagram.data();ListWidgetContent->addItem(msg.left(datagram.size()));}}

服务器端:

#include<QApplication>#include"tcpserver.h"int main(int argc,char *argv[]){QApplication app(argc,argv);QTranslator translator(0);translator.load("tcpserver_wxj",".");app.installTranslator(&translator);TcpServer *tcpserver = new TcpServer();tcpserver->show();return app.exec();}

TCP套接字:在服务器端实现与客户端程序的通信

tcpclientsocket.h

#ifndef TCPCLIENTSOCKET_H#define TCPCLIENTSOCKET_H#include<QtGui>#include<QtNetwork>class TcpClientSocket:public QTcpSocket{Q_OBJECTpublic:TcpClientSocket(QObject *parent=0);~TcpClientSocket();signals:void updateClients(QString,int);void disconnected(int);protected slots:void dataReceived();void slotDisconnected();};#endif
tcpclientsocket.cpp
#include"tcpserver.h"TcpClientSocket::TcpClientSocket(QObject *parent)//构造函数主要制定了信号与槽的连接{connect(this,SIGNAL(readyRead()),this,SLOT(dataReceived()));//readyRead()是QIODevice的sinal,由QTcpSocket继承而来,在有数据到来时发出connect(this,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));//disconnected()信号在断开连接时发出}TcpClientSocket::~TcpClientSocket(){}void TcpClientSocket::dataReceived(){while(bytesAvailable()>0){char buf[1024];int length = bytesAvailable();read(buf,length);QString msg = buf;emit updateClients(msg,length);//通知服务器向聊天室内的所有成员广播信息}}void TcpClientSocket::slotDisconnected(){emit disconnected(this->socketDescriptor());}

Server实现的是一个TCP服务器类,继承QTcpServer,利用QTcpServer,监听到指定端口的TCP连接

server.h

#ifndef SERVER_H#define SERVER_H#include<QtNetwork>#include"tcpclientsocket.h"class Server:public QTcpServer{Q_OBJECTpublic:Server(QObject *parent=0,int port=0);QList<TcpClientSocket*>tcpClientSocketList;//用来保存每一个客户连接的TcpClientSocketsignals:void updateServer(QString,int);public slots:void updateClients(QString,int);void slotDisconnected(int);protected:void incomingConnection(int socketDescriptor);};#endif

server.cpp

#include<QtNetwork>#include"server.h"Server::Server(QObject *parent,int port):QTcpServer(parent){listen(QHostAddress::Any,port);//在指定端口对任意的地址进行监听}void Server::incomingConnection(int socketDescriptor){TcpClientSocket *tcpClientSocket = new TcpClientSocket(this);connect(tcpClientSocket,SIGNAL(updateClients(QString,int)),this,SLOT(updateClients(QString,int)));connect(tcpClientSocket,SIGNAL(disconnected(int)),this,SLOT(slotDisconnected(int)));tcpClientSocket->setSocketDescriptor(socketDescriptor);tcpClientSocketList.append(tcpClientSocket);//将tcpClientSocket加入保存列表}void Server::updateClients(QString msg,int length)//将任意客户端发来的信息进行广播,保证聊天室的所有客户都可以看到{emit updateServer(msg,length);//更新显示状态for(int i=0;i<tcpClientSocketList.count();i++)//实现信息广播{QTcpSocket *item=tcpClientSocketList.at(i);if(item->write(msg.toLatin1(),length)!=length){continue;}}}void Server::slotDisconnected(int descriptor)//从tcpClientSocketList列表中将断开连接的TcpClientSocket对象删除掉{for(int i=0;i<tcpClientSocketList.count();i++){QTcpSocket *item=tcpClientSocketList.at(i);if(item->socketDescriptor()==descriptor){tcpClientSocketList.removeAt(i);return;}}return;}

TcpServer类实现了服务器端的对话框显示与控制

tcpserver.h

#ifndef TCPSERVER_H#define TCPSERVER_H#include<QtGui>#include<QtNetwork>#include"server.h"class TcpServer:public QDialog{Q_OBJECTpublic:TcpServer(QWidget *parent=0,Qt::WindowFlags f=0);~TcpServer();public:QListWidget *ListWidgetContent;QLabel *LabelPort;QLineEdit *LineEditPort;QPushButton *PushButtonCreate;int port;Server *server;public slots:void slotCreateServer();void updateServer(QString,int);};#endif

tcpserver.cpp

#include"tcpserver.h"TcpServer::TcpServer(QWidget *parent,Qt::WindowFlags f):QDialog(parent,f)//空间的布局{QFont font("ZYSong18030",12);setFont(font);setWindowTitle(tr("TCP Server"));QVBoxLayout *vbMain = new QVBoxLayout(this);ListWidgetContent =  new QListWidget(this);vbMain->addWidget(ListWidgetContent);QHBoxLayout *hb = new QHBoxLayout();LabelPort = new QLabel(this);LabelPort->setText(tr("Port"));hb->addWidget(LabelPort);LineEditPort = new QLineEdit(this);hb->addWidget(LineEditPort);vbMain->addLayout(hb);PushButtonCreate = new QPushButton(this);PushButtonCreate->setText(tr("Create"));vbMain->addWidget(PushButtonCreate);connect(PushButtonCreate,SIGNAL(clicked()),this,SLOT(slotCreateServer()));port = 8010;LineEditPort->setText(QString::number(port));}TcpServer::~TcpServer(){}void TcpServer::slotCreateServer()//创建TCP服务器{server = new Server(this,port);connect(server,SIGNAL(updateServer(QString,int)),this,SLOT(updateServer(QString,int)));PushButtonCreate->setEnabled(false);}void TcpServer::updateServer(QString msg,int length)//更新服务器端的信息显示{ListWidgetContent->addItem(msg.left(length));}

运行图:



原创粉丝点击