聊天程序:
QT实现的界面
网络的数据通信
服务器端:
建立用户UI
建立服务器socket
接受客户连接
为每个各户建立线程处理客户数据
设计界面
QMainWindow 增加:菜单,工具条,状态条
菜单:
QMenuBar
addMenu
QMenu
addAction
QMenuItem/QAction
构造器
菜单的响应
状态条
QStatusBar
chatServer
charServer.cpp
#include<QApplication>
#include “ServerWindow.h”
#include<QTextCodec>
int main(int args , char ** argv)
{
QApplication app(args , argv);
QTextCodec * codec=QTextCodec::codecForName(“utf-8”);
QTextCodec::setCodecForTr(codec);
ServerWindow sw;
return app.exec();
}
charServer.pro
TEMPLATE=app
SOURCES=charServer.cpp \
ServerWindow.cpp \
chatException.cpp \
ServerSocket.cpp \
ThAccept.cpp \
ThClient.cpp
HEADERS=ServerWindow.h chatException.hServerSocket.h ThAccept.h ThClient.h
CONFIG=release qt
QT=core gui
TARGET=charServer
ServerWindow.h
#ifndef SERVER_WINDOW_H
#define SERVER_WINDOOW_H
#include<QMainWindow>
#include<QWidget>
#include<QTextEdit>
#include<QMenuBar>
#include<QMenu>
#include<QAction>
#include<QStatusBar>
#include<QLabel>
#include “ThAccept.h”
#include<list>
#include “ThClient.h”
using namespace std;
class ServerWindow :public QMainWindow
{
Q_OBJECT
public:
static list<ThClient*>allusers;
private:
QTextEdit *info;
//菜单
QMenuBar * bar;
QMenu *mnuserver;
QAction *actstart;
QAction *actexit;
//状态条
QStatusBar *status;
QLabel *lbltip;
QLabel *lblresult;
QLabel *lbltim;
//接收线程
ThAccept thaccept;
public:
ServerWindow(QWidget *p=NULL);
public slots:
void onStart(); //菜单点击的槽函数
};
#endif
ServerWindow.cpp
#include “ServerWindow.h”
#include<QColor>
#include<QMessageBox>
#include “ChatException”
list<ThClient*> ServerWindow::allusers;
void ServerWindow::onStart()
{
//QMessageBox::information(this,tr(“提示”),tr(“响应”));
try
{
thaccept.init();
thaccept.info=info;
info->setTextColor(QColor(0,255,0));
info->append(tr(“服务器启动成功!”));
connect(&thaccept , SIGNAL(sigInfo(const QString &)) ,
info,SLOT(append(const QString&)));
thaccept.start();
info->append(tr(“服务器接收线程启动!”));
}
catch(ChatException e)
{
info->setTextColor(QColor(255,0,0));
info->apped(tr(e.what()));
}
}
ServerWindow::ServerWindow(QWidget*p):QMainWindow(p)
{
//初始化窗体
this->resize(1366,768);
this->move(0,0);
this->setWindowTitle(tr(“聊天服务器”));
//初始化组件
info = new QTextEdit;
info->setTextColor(QColor(255,0,0));
info->append(tr(“欢迎使用聊天程序”));
info->append(tr(“===============”));
info->setTextColor(QColor(0,255,255));
info->setFontPointSize(20);
this->setCentralWidget(info); //设置窗体的中间组件
// 初始化菜单
bar = new QMenuBar(this);
mnuserver = new QMenu(tr(“服务器”),bar);
actstart= new QAction(tr(“启动服务器”),mnuserver);
actexit = new QAction(tr(“退出”),mnuserver);
//菜单关系维护
mnuserver->addAction(actstart);
mnuserver->addSeparator(); //菜单添加分割条
mnuserver->addAction(actexit);
bar->addMenu(mnuserver);
this->setMenuBar(bar);
//初始化状态条
status = new QStatusBar(this);
lbltip = new QLabel(tr(“提示”),status);
lblresult = new QLabel(tr(“操作结果显示”),status);
lbltim = new QLable(tr(“2010-11-24”),status);
lbltim->setFrameShape(QFrame::Panel); //设置边框
//维护关系
status->addPermanentWidget(lbltip,300); //300为最小的大小
status->addPermanentWidget(lblresult,500);
status->addPermanentWidget(lbltim,0); //0为默认剩余大小
this->setStatusBar(status);
connect(actstart , SIGNAL(triggered) ,
this,SLOT(onStart()));
this->setVisible(true);
}
//异常类
chatException.h
#ifndef CHAT_EXCEPTION_H
#define CHAT_EXCEPTION_H
#include<exception>
using namespace std;
class ChatException :public exception
{
private:
char msg[50]; //错误信息的描述
public:
ChatException();
ChatException(const char *);
const char * what() const throw();
};
#endif
chatException.cpp
#include “chatException.h”
#include<cstdlib>
#include<cstring.h>
#include<cstdio>
using namespace std;
ChatException::CharException()
{
memset(msg,0,sizeof(msg));
sprintf(msg, “聊天异常!”);
}
ChatException::CharException(const char *m)
{
memset(msg,0,sizeof(msg));
sprintf(msg, “聊天异常:%s”,m);
}
const char * ChatException::what() const throw()
{
return msg;
}
ServerSocket.h
#ifndef SERVER_SOCKET_H
#define SERVER_SOCKET_H
#include<QObject>
#include “chatException.h”
class ServerSocket : public QObject
{
Q_OBJECT
public:
char ip[30];
short port;
int fd;
public:
void initSocket() throw (ChatException);
int accept() throw(ChatExceotion);
};
#endif
ServerSocket.cpp
#include “ServerSocket.h”
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
void ServerSocket::initSocket() throw(ChatException)
{
struct sockaddr_in addr;
int r;
fd=socket(AF_INET,SOCK_STREAM,0);
if(fd== -1) throw ChatException(“socket错误”);
addr.sin_family=AF_INET;
addr.sin_port=htons(port);
addr.sin_addr.s_addr=inet_addr(ip);
r=bind(fd,(struct sockaddr*)&addr,sizeof(addr));
if(r== -1)
{
close(fd);
throw ChatException(“bind错误”);
}
r=listen(fd,10);
if(r == -1)
{
close(fd);
throw ChatException(“listen 错误”);
}
}
int ServerSocket::accept()throw(ChatExceotion)
{
int cfd;
cfd=::accept(fd,NULL,0);
if(cfd == -1) throw ChatException(“accept错误”);
return cfd;
}
ThAccept.h
#ifndef TH_ACCEPT_H
#define TH_ACCEPT_H
#include<QThread>
#include “ChatException.h”
#include “ServerSocket.h”
#include <QTextEdit>
class ThAccept :public QThread,public QObject
{
Q_OBJECT
public:
QTextEdit *info;
private:
ServerSocket server;
public:
void init() throw(ChatException);
void run(); //在线程中接收客户连接
public: signal:
void sigInfo(const QString &);
};
#endif
ThAccept.cpp
#include “ThAccpet.h”
#include<cstdio>
#include “ThClient.h”
#include “ServerWindow.h”
using namespace std;
void ThAccept::init() throw(ChatException)
{
sprintf(server.ip, “%s”,“127.0.0.1”);
server.port=8888;
try
{
Server.initSocket();
}
catch(ChatException e)
{
throw e;
}
}
void ThAccept::run()
{
while(true)
{
try
{
int fd=server.accept();
//发出信号
emit sigInfo(tr(“有人连接!”));
//建立子线程监听对应客户
ThClient *th=new ThClient ;
th->fd=fd;
ServerWindow::alluser.push_back(th);
connect(th ,SIGNAL(sigInfo(const QString&)),
info,SLOT(append(const QString&)));
th->start();
}
catch(ChatException e)
{
//发出信号
emit sigInfo(tr(“服务器崩溃!”));
break;
}
}
}
ThClient.h
#ifnedf TH_CLIENT_H
#define TH_CLIENT_H
#include<QThread>
class ThClient : public QThread
{
Q_OBJECT
public:
int fd;
void run(); //接收客户数据,广播
public:signals:
void sigInfo(const QString&);
};
#endif
ThClient.cpp
#include “ThClient.h”
#include<sys.socket.h>
#include<list>
#include “ServerWindow.h”
#include<unistd.h>
using namespace std;
void ThClient::run()
{
int r;
char buf[1024];
while(true)
{
r=recv(fd , buf ,sizeof(buf)-1,0);
if(r<=0)
{
//emit
emit sigInfo(tr(“有客户退出!”));
ServerWindow::alluser.remove(this);
close(fd);
// delete this;
break;
}
buf[r]= ‘\n’;
//发送消息,把接收数据显示服务器主窗体
emit sigInfo(tr(buf));
//广播
list<ThClient*>::iterator it= ServerWindow::allusers.begin();
while(it!=ServerWindow::allusers.end())
{
send((*it)->fd , buf ,strlen(buf),0);
it++;
}
}
}