专业课程设计之客户与服务器程序的同步与通信机制的设计(二)TCP通信
源碼下載地址為:
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有一個idint 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,"");}} }
所以服務器的部分就結束了。
下面看客戶機的,如下圖所示:
運行界面如下:
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_OBJECTpublic: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; // 定時器IDint AutoInrestatus;int randomNum;int speed; //毫秒public slots:void slotEnter();void slotConnected();void slotDisconnected();void dataReceived();void slotSend();void ConsumeBtnEvent();void AutoConsumeBtnEvent(); };#endif // WIDGET_Hwidget.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();//服務器主動刷新Finalif(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
---------------------------------------------------------------------------------------------------------------------------------------------------------
總結
以上是生活随笔為你收集整理的专业课程设计之客户与服务器程序的同步与通信机制的设计(二)TCP通信的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 丘成桐中学计算机科学奖,丘成桐中学科学奖
- 下一篇: c# 再次尝试 连接失败_[图]连接US