日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

专业课程设计之客户与服务器程序的同步与通信机制的设计(二)TCP通信

發布時間:2025/3/15 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 专业课程设计之客户与服务器程序的同步与通信机制的设计(二)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,"");}} }


那么服務器改如何對客戶機的數據進行處理呢?在server.cpp里面是這樣處理的:

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_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_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();//服務器主動刷新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通信的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。