学习一点TCP网络协议的知识,利用Qt做一次调查问卷,客户端与服务器端如下:
服务器:
客户端:
客户端:
首先在创建的tcpclient工程下的tcpclient.pro中加入
QT += network
然后编写tcpclient.h
#ifndef TCPCLIENT_H
#define TCPCLIENT_H
#include <QDialog>
#include <QListWidget>
#include <QCheckBox>
#include <QPushButton>
#include <QLabel>
#include <QGridLayout>
#include <QHostAddress>
#include <QTcpSocket>
#include <QButtonGroup>
#include <QLineEdit>
class TcpClient : public QDialog
{
Q_OBJECT
public:
TcpClient(QWidget *parent = 0,Qt::WindowFlags f=0);
~TcpClient();
private:
QString username1;
QPushButton *saveBtn;
QPushButton *submitBtn;
QLabel *title;
QLineEdit *lineedit1;
QLabel *username;
QPushButton *yesbutton;
QLabel *question1;
QLabel *question2;
QLabel *question3;
QLabel *question31;
QLabel *question32;
QLabel *question33;
QLabel *question34;
QButtonGroup *answer1;
QButtonGroup *answer2;
QButtonGroup *answer3A;
QButtonGroup *answer3B;
QButtonGroup *answer3C;
QButtonGroup *answer3D;
QCheckBox *answer11;
QCheckBox *answer12;
QCheckBox *answer13;
QCheckBox *answer21;
QCheckBox *answer22;
QCheckBox *answer311;
QCheckBox *answer312;
QCheckBox *answer321;
QCheckBox *answer322;
QCheckBox *answer331;
QCheckBox *answer332;
QCheckBox *answer341;
QCheckBox *answer342;
QGridLayout *mainLayout;
bool savestatus;
bool submitstatus;
int port;
QHostAddress *serverIP;
QTcpSocket *tcpSocket;
public slots:
QString slotSave();
void slotConnected();
void getname();
void slotSaveBox();
void dataReceived();
void slotSubmit();
QString slotAnswer1();
QString slotAnswer2();
};
#endif // TCPCLIENT_H
tcpclient.cpp
#include "tcpclient.h"
#include <QMessageBox>
#include <QHostInfo>
TcpClient::TcpClient(QWidget *parent,Qt::WindowFlags f)
: QDialog(parent,f)
{
setWindowTitle(tr("问卷调查"));
title = new QLabel(tr("TMD疼痛筛查表"));
QPalette pe;
pe.setColor(QPalette::WindowText,Qt::red);
title->setPalette(pe);
lineedit1 = new QLineEdit(this);
username = new QLabel(tr("用户名"));
yesbutton = new QPushButton(tr("确认"));
saveBtn = new QPushButton(tr("保存"));
savestatus = false;
saveBtn->setEnabled(false);
submitBtn = new QPushButton(tr("提交"));
submitstatus = false;
submitBtn->setEnabled(false);
question1 = new QLabel(tr("1.最近30天内,任一侧的下颌或太阳穴部位的疼痛持续了多久?"));
answer11 = new QCheckBox(tr("a.没有疼痛"));
answer12 = new QCheckBox(tr("b.断断续续"));
answer13 = new QCheckBox(tr("c.一直有疼痛"));
answer1 = new QButtonGroup(this);
answer1->addButton(answer11);
answer1->addButton(answer12);
answer1->addButton(answer13);
question2 = new QLabel(tr("2.最近30天内,醒来时下颌是否感觉疼痛或者僵硬?"));
answer21 = new QCheckBox(tr("a.是"));
answer22 = new QCheckBox(tr("b.否"));
answer2 = new QButtonGroup(this);
answer2->addButton(answer21);
answer2->addButton(answer22);
// question31
mainLayout = new QGridLayout(this);
mainLayout->addWidget(title,0,1,1,1,Qt::AlignCenter);
mainLayout->addWidget(username,2,0,1,1);
mainLayout->addWidget(lineedit1,2,2,1,1);
mainLayout->addWidget(yesbutton,2,3,1,1);
mainLayout->addWidget(submitBtn,2,4,1,1);
mainLayout->addWidget(question1,3,0,1,0);
mainLayout->addWidget(answer11,4,0,1,1);
mainLayout->addWidget(answer12,5,0,1,1);
mainLayout->addWidget(answer13,6,0,1,1);
mainLayout->addWidget(question2,8,0,1,0);
mainLayout->addWidget(answer21,9,0,1,1);
mainLayout->addWidget(answer22,10,0,1,1);
mainLayout->addWidget(saveBtn,20,1,1,1,Qt::AlignCenter);
port = 8010;
serverIP =new QHostAddress();
QString ip = "127.0.0.1";
serverIP->setAddress(ip);
tcpSocket = new QTcpSocket(this);
connect(tcpSocket,SIGNAL(connected()),this,SLOT(slotConnected()));
tcpSocket->connectToHost(*serverIP,port);
connect(saveBtn,SIGNAL(clicked(bool)),this,SLOT(slotSave()));
connect(saveBtn,SIGNAL(clicked(bool)),this,SLOT(slotSaveBox()));
connect(submitBtn,SIGNAL(clicked(bool)),this,SLOT(slotSubmit()));
//问题1
connect(answer11,SIGNAL(clicked(bool)),this,SLOT(slotAnswer1()));
connect(answer12,SIGNAL(clicked(bool)),this,SLOT(slotAnswer1()));
connect(answer13,SIGNAL(clicked(bool)),this,SLOT(slotAnswer1()));
//问题2
connect(answer21,SIGNAL(clicked(bool)),this,SLOT(slotAnswer2()));
connect(answer22,SIGNAL(clicked(bool)),this,SLOT(slotAnswer2()));
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(dataReceived()));
connect(yesbutton,SIGNAL(clicked(bool)),this,SLOT(getname()));
}
void TcpClient::slotConnected()
{
savestatus = true;
saveBtn->setEnabled(savestatus);
}
void TcpClient::getname()
{
username1 = lineedit1->text();
}
QString TcpClient::slotAnswer1()
{
QString msg1;
if(answer11->isChecked()==true)
{
msg1 = "a" ;
return msg1;
}
if(answer12->isChecked()==true)
{
msg1 = "b" ;
return msg1;
}
if(answer13->isChecked()==true)
{
msg1 = "c" ;
return msg1;
}
else
{
msg1 = "quetion1 has no answer";
return msg1;
}
}
QString TcpClient::slotAnswer2()
{
QString msg2;
if(answer21->isChecked()==true)
{
msg2 = "a" ;
return msg2;
}
if(answer22->isChecked()==true)
{
msg2 = "b" ;
return msg2;
}
else
{
msg2 = "question2 has no answer";
return msg2;
}
}
QString TcpClient::slotSave()
{
submitstatus = true;
submitBtn->setEnabled(savestatus);
QString msgsave;
msgsave =username1+":\nThe answer1 is: "+ slotAnswer1()+ "\nThe answer2 is: "+ slotAnswer2()+"\n end"; //给服务器发送信息
return msgsave;
}
void TcpClient::slotSubmit()
{
QString msgsubmit = slotSave();
submitstatus = false;
submitBtn->setEnabled(submitstatus);
tcpSocket->write(msgsubmit.toLatin1(),msgsubmit.length());
}
void TcpClient::slotSaveBox()
{
QMessageBox::information(NULL, "Title", "保存成功", QMessageBox::Ok); //返回消息框
}
void TcpClient::dataReceived()
{
while(tcpSocket->bytesAvailable()>0)
{
QByteArray datagram;
datagram.resize(tcpSocket->bytesAvailable());
tcpSocket->read(datagram.data(),datagram.size());
QString msg=datagram.data();
if(msg.left(datagram.size())=="OK"+0)
{
QMessageBox::information(NULL, "Title", "提交成功", QMessageBox::Ok);
}
}
}
TcpClient::~TcpClient()
{
}
服务器:
同样地需要在tcpserver.pro中加入 QT = +network 语句
tcpclientsocket.h
#ifndef TCPCLIENTSOCKET_H
#define TCPCLIENTSOCKET_H
#include <QTcpSocket>
#include <QObject>
class tcpclientsocket : public QTcpSocket
{
Q_OBJECT
public:
tcpclientsocket(QObject *parent=0);
signals:
void updataClients(QString,int);
protected slots:
void dataReceived();
};
#endif // TCPCLIENTSOCKET_H
tcpclientsocket.cpp
#include "tcpclientsocket.h"
tcpclientsocket::tcpclientsocket(QObject *parent)
{
connect(this,SIGNAL(readyRead()),this,SLOT(dataReceived()));
}
void tcpclientsocket::dataReceived()
{
while(bytesAvailable()>0)
{
int length = bytesAvailable();
char buf[1024];
read(buf,length);
QString msg=buf;
emit updataClients(msg,length); //发送信号
}
}
server.h
#ifndef SERVER_H
#define SERVER_H
#include "tcpclientsocket.h"
#include <QTcpServer>
#include <QObject>
class Server : public QTcpServer
{
Q_OBJECT
public:
Server(QObject *parent=0,int port=0);
QList<tcpclientsocket*>tcpClientSocketList;
signals:
void updataServer(QString,int);
public slots:
void updataClients(QString,int);
protected:
void incomingConnection(int socketDescriptor);
};
#endif // SERVER_H
server.cpp
(这里写得很不好,但因为对网络TCP协议理解尚且较浅,就以实现目的为先了。)
#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(updataClients(QString,int)),
this,SLOT(updataClients(QString,int)));
tcpClientSocket->setSocketDescriptor(socketDescriptor);
tcpClientSocketList.append(tcpClientSocket);
}
void Server::updataClients(QString msg, int length)
{
emit updataServer(msg,length);
QString msg1 = "OK"+0; //发送OK+0,我默认了另一个服务器是第0个,这也是这里最大的问题;因为利用 //循化后程序无法达到理想状况。 QTcpSocket *item = tcpClientSocketList.at(0);
item->write(msg1.toLatin1(),msg1.length());
}
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include "server.h"
#include <QDialog>
#include <QListWidget>
#include <QPushButton>
#include <QGridLayout>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QListWidget *ContentWidget;
QPushButton *CreateBtn;
QGridLayout *mainLayout;
int port;
Server *server;
QTcpSocket *tcpsocketreturn1;
public slots:
void slotCreateServer();
void updateServer(QString,int);
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include<QtDebug>
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
port=8010;
setWindowTitle(tr("服务器显示"));
ContentWidget = new QListWidget;
CreateBtn = new QPushButton("创建");
mainLayout = new QGridLayout(this);
mainLayout->addWidget(ContentWidget,0,0,1,2);
mainLayout->addWidget(CreateBtn,2,0,1,2);
connect(CreateBtn,SIGNAL(clicked(bool)),this,SLOT(slotCreateServer()));
}
void Dialog::slotCreateServer()
{
qDebug() <<"created";
server = new Server(this,port);
connect(server,SIGNAL(updataServer(QString,int)),this,SLOT(updateServer(QString,int)));
CreateBtn->setEnabled(false);
}
void Dialog::updateServer(QString msg, int length)
{
ContentWidget->addItem(msg.left(length));
ContentWidget->addItem("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
Dialog::~Dialog()
{
}
然后先运行服务器程序,点击创建后即可建立连接(只有建立连接,客户端才可以将答案保存到变量中):
在填写好用户名后,点击确认并开始选择答案。选择好之后,点击保存,此时提交通道打开(即可以点击提交):
然后点击提交按钮,即可将数据发送到服务器端:
此时服务器端会发送一个“OK”+0到客户端,客户端响应后弹出“提交成功”的消息框:
这样就完成了一个简陋的调查问卷!
本次用Qt,我又有了2点对Qt的新的认识
1.Qt中的信号不一定非要是控件(如按钮按下)产生,也可以是人为发出,提交了程序的灵活性。而且在同一工程中,信号名字在不同文件中是可以相同的,且可以互相连接,加深了我对信号与槽的理解(即这一机制是由对象和函数组成共同组成的的)
2.Qt中槽函数和其他函数有许多相似性,也可以返回值(答案的返回我是这么实现的),只是它接收信号之后执行而已(槽函数又像是满足一定条件时被调用的函数,与之前学习的单片机中的中断函数很像,不过是“激活”条件不一样)。