源码下载地址为:
http://download.csdn.net/detail/qq78442761/9856423
---------------------------------------------------------------------------------------------------------------------------------------------------------
上一节为项目介绍,未读的博友请先阅读:
http://blog.csdn.net/qq78442761/article/details/72819181
---------------------------------------------------------------------------------------------------------------------------------------------------------
关于TCP通信下面说明下TCP的流程:
所以TCP服务器,初始化,绑定,监听,接收连接,然后处理
注意:本IDE为QtCreator5.7,请用5以上的版本打开。
服务器源码如下图:
服务器如何TCP服务器,初始化,绑定,监听,接收连接,然后处理,如何实现这些功能呢?
在Server.h里面提供了这些过程:
#ifndef SERVER_H
#define SERVER_H
#include <QTcpServer>
#include <QObject>
#include <QMutex>
#include <QTimerEvent>
#include "tcpclientsocket.h"
#include "resource.h"
class Server : public QTcpServer
{
Q_OBJECT
public:
Server(QObject *parent=0,int port=0);
QList<TcpClientSocket*> tcpClientSocketList;
virtual void timerEvent ( QTimerEvent * event );
bool resourceNumReduce(int reduceNum);
signals:
void updateServer(QString,int);
public slots:
void updateClients(QString,int,QHostAddress,QString);
void slotDisconnected(int);
protected:
void incomingConnection(int socketDescriptor);
private:
int m_timerId; // 每个Timer有一个id
int resourceNumTemp;
int peerNameInt;
};
#endif // SERVER_H
注意:具体是如何实现的呢?此处,不再说明,具体去看.cpp文件。本文开头提供源码和程序下载
如何得到连接上的客户端的信息的
这是tcpclientsocket.h所做的事情,源码如下:
#ifndef TCPCLIENTSOCKET_H
#define TCPCLIENTSOCKET_H
#include <QTcpSocket>
#include <QHostAddress>
#include <QObject>
class TcpClientSocket : public QTcpSocket
{
Q_OBJECT
public:
TcpClientSocket(QObject *parent=0);
signals:
void updateClients(QString,int,QHostAddress,QString);
void disconnected(int);
protected slots:
void dataReceived();
void slotDisconnected();
};
#endif // TCPCLIENTSOCKET_H
如何实现客户机是消耗产品,还是单纯的连接产品呢?
下面这个函数给出了解决办法:
void TcpClientSocket::dataReceived()
{
while(bytesAvailable()>0)
{
QHostAddress ipAddress;
QString port;
int length=bytesAvailable();
QByteArray datagram;
datagram.resize(bytesAvailable());
read(datagram.data(),datagram.size());
QString msg=QString::fromLocal8Bit(datagram);
//判断是不是要消耗产品,如果要就记录IP和端口号
if(msg.startsWith("B"))
{
//记录IP和端口号
ipAddress=this->peerAddress();
port=QString::number(this->peerPort());
emit updateClients(msg,length,ipAddress,port);
}
else
{
//单纯的连接服务器
emit updateClients(msg,length,ipAddress,"");
}
}
}
void Server::updateClients(QString msg, int length, QHostAddress ip, QString port)
{
resourceNumTemp=Resource::getResourceNum();
//服务器主动更新客户机
if(msg.startsWith("Final"))
{
msg=msg.append(QString::number(Resource::getResourceNum(),10));
msg=msg.append(".");
int msgResourceNumLength=msg.length();
for(int i=0;i<tcpClientSocketList.count();i++)
{
QTcpSocket *item=tcpClientSocketList.at(i);
//qDebug()<<msg;
if(item->write(msg.toLocal8Bit())!=msgResourceNumLength)
{
continue;
}
}
return;
}
//客户连接
if(msg.startsWith('Z'))
{
emit updateServer(msg,msg.length());
}
//对单个客户操作
if(!port.isEmpty())
{
//提取用户名和数字
QStringList list = msg.split(".");
QString Name=list[1];
QString Num=list[2];
if(resourceNumReduce(Num.toInt()))
{
for(int i=0;i<tcpClientSocketList.count();i++)
{
QTcpSocket *item=tcpClientSocketList.at(i);
if(item->peerAddress()==ip && item->peerPort()==port.toInt())
{
QString msg="B.商品消耗成功!.";
item->write(msg.toLocal8Bit());
msg="B.";
msg=msg.append(Name);
msg=msg.append(".");
msg=msg.append(Num);
emit updateServer(msg,msg.length());
return;
}
}
}
else //产品数量不够,客户消耗失败
{
for(int i=0;i<tcpClientSocketList.count();i++)
{
QTcpSocket *item=tcpClientSocketList.at(i);
if(item->peerAddress()==ip && item->peerPort()==port.toInt())
{
QString msg="C.商品消耗失败!.";
item->write(msg.toLocal8Bit());
msg="C.";
msg=msg.append(Name);
msg=msg.append(".");
msg=msg.append(Num);
emit updateServer(msg,msg.length());
return;
}
}
}
}
//对单个客户操作
//更新客户端产品数量
QString msgResourceNum="A.";
msgResourceNum=msgResourceNum.append(QString::number(Resource::getResourceNum(),10));
msgResourceNum=msgResourceNum.append(".");
int msgResourceNumLength=msgResourceNum.length();
for(int i=0;i<tcpClientSocketList.count();i++)
{
QTcpSocket *item=tcpClientSocketList.at(i);
if(item->write(msgResourceNum.toLocal8Bit())!=msgResourceNumLength)
{
continue;
}
}
}
所以服务器的部分就结束了。
下面看客户机的,如下图所示:
运行界面如下:
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QListWidget>
#include <QTimerEvent>
#include <QCloseEvent>
#include <QPushButton>
#include <QHostAddress>
#include <QTcpSocket>
#include <QMessageBox>
#include <stdlib.h>
#include <time.h>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
virtual void timerEvent(QTimerEvent *event);
virtual void closeEvent(QCloseEvent *event);
~Widget();
private:
Ui::Widget *ui;
bool status;
int port;
QHostAddress *serverIP;
QString userName;
QTcpSocket *tcpSocket;
int m_timerId; // 定时器ID
int AutoInrestatus;
int randomNum;
int speed; //毫秒
public slots:
void slotEnter();
void slotConnected();
void slotDisconnected();
void dataReceived();
void slotSend();
void ConsumeBtnEvent();
void AutoConsumeBtnEvent();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <qDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
srand((unsigned) time(NULL)); //用时间做种,每次产生随机数不一样
QString NameArr[40]={"刘一","陈二","张三","李四","王五","赵六","孙七"
,"周八","吴九","郑十","小明","小黄","小白","小红"
,"小黑","小绿","大明","大黄","大白","大红","大黑"
,"大绿","小哈","乌龟","蚂蚁","螃蟹","蜻蜓","飞机"
,"坦克","大炮","火箭","蘑菇头","朱小明","陈翔","点点"
,"闰土","茅台","妹爷","球球","腿腿"};
int number = rand() % 41; //产生0-24的随机数
userName=NameArr[number];
AutoInrestatus=0;
this->setWindowTitle(tr("客户端"));
this->setFixedSize(this->width(),this->height());
ui->IplineEdit->setText("127.0.0.1");
ui->NamelineEdit->setText(userName);
port=9999;
status=false;
ui->PortlineEdit->setText(QString::number(port));
serverIP=new QHostAddress();
ui->AutoConsumepushButton->setEnabled(false);
ui->OkConsumepushButton->setEnabled(false);
connect(ui->LinkSocketpushButton,SIGNAL(clicked(bool)),this,SLOT(slotEnter()));
connect(ui->OkConsumepushButton,SIGNAL(clicked(bool)),this,SLOT(ConsumeBtnEvent()));
connect(ui->AutoConsumepushButton,SIGNAL(clicked(bool)),this,SLOT(AutoConsumeBtnEvent()));
}
void Widget::timerEvent(QTimerEvent *event)
{
if(ui->resourceNumlabel->text().toInt()==0)
{
QString msgFail="商品号为0,不能发送消息给服务器!";
QListWidgetItem *msg_Item=new QListWidgetItem(msgFail);
msg_Item->setTextColor(0xff969696);
ui->ContenListWidget->insertItem(0,msg_Item);
return;
}
QString msg="B."+userName+".1.";
tcpSocket->write(msg.toLocal8Bit());
}
void Widget::closeEvent(QCloseEvent *event)
{
if(status)
{
switch( QMessageBox::information(this,tr("提示"),tr("你确定退出该软件?"),tr("确定"), tr("取消"),0,1))
{
case 0:
status=1;
slotEnter();
event->accept();
break;
case 1:
default:
event->ignore();
break;
}
}
}
void Widget::AutoConsumeBtnEvent()
{
AutoInrestatus++;
if(AutoInrestatus%2==0) //偶数为没有自增的情况(或想让他停止自增)
{
ui->AutoConsumepushButton->setText("自动消耗");
killTimer(m_timerId); // 关闭定时器
}
else //奇数为在自增(或,想让他自增)
{
m_timerId = startTimer(ui->speedlineEdit->text().toInt());
ui->AutoConsumepushButton->setText("停止消耗");
}
}
void Widget::ConsumeBtnEvent()
{
if(ui->ConsumelineEdit->text().isEmpty())
{
QMessageBox::information(this,tr("error"),tr("ConsumelineEdit is empty!"));
return;
}
QString msg="B."+userName+"."+ui->ConsumelineEdit->text()+".";
if(ui->resourceNumlabel->text().toInt()==0)
{
QString msgFail="商品号为0,不能发送消息给服务器!";
QListWidgetItem *msg_Item=new QListWidgetItem(msgFail);
msg_Item->setTextColor(0xff969696);
ui->ContenListWidget->insertItem(0,msg_Item);
return;
}
tcpSocket->write(msg.toLocal8Bit());
ui->ConsumelineEdit->text();
}
void Widget::slotEnter()
{
if(!status)
{
QString ip = ui->IplineEdit->text();
if(!serverIP->setAddress(ip))
{
QMessageBox::information(this,tr("error"),tr("server ip address error!"));
return;
}
if(ui->NamelineEdit->text()=="")
{
QMessageBox::information(this,tr("error"),tr("User name error!"));
return;
}
userName=ui->NamelineEdit->text();
tcpSocket = new QTcpSocket(this);
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);
status=true;
}
else
{
int length=0;
QString msg_demo=userName+tr("】断开服务器");
QString msg="Z.【";
msg=msg.append(msg_demo);
// if((length=tcpSocket->write(msg.toUtf8(),msg.length()))!=msg. length())
// {
// return;
// }
// tcpSocket->disconnectFromHost();
// status=false;
QByteArray datasendEn=msg.toLocal8Bit();
length=tcpSocket->write(datasendEn);
tcpSocket->disconnectFromHost();
status=false;
}
}
void Widget::slotConnected()
{
ui->AutoConsumepushButton->setEnabled(true);
ui->OkConsumepushButton->setEnabled(true);
ui->NamelineEdit->setEnabled(false);
ui->IplineEdit->setEnabled(false);
ui->PortlineEdit->setEnabled(false);
ui->LinkSocketpushButton->setText(tr("断开服务器"));
int length=0;
QString msg_demo=userName+tr("】连接服务器");
QString msg="Z.【";
msg=msg.append(msg_demo);
QByteArray datasendBg=msg.toLocal8Bit();
if((length=tcpSocket->write(datasendBg))!=msg.length())
{
return;
}
}
void Widget::slotSend()
{
}
void Widget::slotDisconnected()
{
ui->NamelineEdit->setEnabled(true);
ui->IplineEdit->setEnabled(true);
ui->PortlineEdit->setEnabled(true);
ui->AutoConsumepushButton->setEnabled(false);
ui->OkConsumepushButton->setEnabled(false);
ui->LinkSocketpushButton->setText(tr("连接服务器"));
}
void Widget::dataReceived()
{
while(tcpSocket->bytesAvailable()>0)
{
QByteArray datagram;
datagram.resize(tcpSocket->bytesAvailable());
tcpSocket->read(datagram.data(),datagram.size());
QString msg=QString::fromLocal8Bit(datagram);
qDebug()<<msg;
//判断协议
char *msgTochTest;
QByteArray ba = msg.toLocal8Bit();
msgTochTest=ba.data();
//服务器主动刷新Final
if(msgTochTest[0]=='F')
{
QStringList listTemp = msg.split(".");
QString msgupdate="服务器主动更新,数量为:";
msgupdate=msgupdate.append(listTemp[1]);
QListWidgetItem *msg_Item=new QListWidgetItem(msgupdate);
ui->resourceNumlabel->setText(listTemp[1]);
msg_Item->setTextColor(0x800080);
ui->ContenListWidget->insertItem(0,msg_Item);
}
//头字母为C说明商品消耗失败
if(msgTochTest[0]=='C')
{
QStringList listTemp = msg.split(".");
QString msgFail=listTemp[1];
QListWidgetItem *msg_Item=new QListWidgetItem(msgFail);
msg_Item->setTextColor(0xffff0000);
ui->ContenListWidget->insertItem(0,msg_Item);
}
//头字母为B说明商品消耗成功
if(msgTochTest[0]=='B')
{
QStringList listTemp = msg.split(".");
QString msgSucc=listTemp[1];
QListWidgetItem *msg_Item=new QListWidgetItem(msgSucc);
msg_Item->setTextColor(0xff0000ff);
ui->ContenListWidget->insertItem(0,msg_Item);
}
//头字母为A说明刷新产品数量
if(msgTochTest[0]=='A')
{
QStringList listTemp = msg.split(".");
QString msgSucc=listTemp[1];
ui->resourceNumlabel->setText(msgSucc);
QString msgItem="获得服务器产品更新消息,产品更新后为:";
msgItem=msgItem.append(msgSucc);
ui->ContenListWidget->insertItem(0,msgItem);
}
//ui->ContenListWidget->addItem(msg.left(datagram.size()));
}
}
Widget::~Widget()
{
delete ui;
}
此处和服务器很类似在此不再说明、
下面一节说数据共享,和互斥锁,和Qt中线程的创建
链接如下:http://blog.csdn.net/qq78442761/article/details/72819470