分類: C/C++
TCP
TCP是一個基於流的協議。對於應用程序,數據表現為一個長長的流,而不是一個大大的平面文件。基於TCP的高層協議通常是基於行的或者基於塊的。
●、基於行的協議把數據作為一行文本進行傳輸,每行都以一個換行符結尾。
●、基於塊的協議把數據作為二進制塊進行傳輸,每塊是由一個size大小字段和緊跟它的一個size字節的數據組成。
QTcpSocket通過器父類QAbstractSocket繼承了QIODevice,因此他可以通過使用QTextStream和QDataStream來進行讀取和寫入。
QTcpServer類在服務器端處理來自TCP客戶端連接數據,需要注意的是,該類直接繼承於QObject基類,而不是QAbstractSocket抽象套接字類。
TCP是一個基於流的協議。對於應用程序,數據表現為一個長長的流,而不是一個大大的平面文件。基於TCP的高層協議通常是基於行的或者基於塊的。
●、基於行的協議把數據作為一行文本進行傳輸,每行都以一個換行符結尾。
●、基於塊的協議把數據作為二進制塊進行傳輸,每塊是由一個size大小字段和緊跟它的一個size字節的數據組成。
QTcpSocket通過器父類QAbstractSocket繼承了QIODevice,因此他可以通過使用QTextStream和QDataStream來進行讀取和寫入。
QTcpServer類在服務器端處理來自TCP客戶端連接數據,需要注意的是,該類直接繼承於QObject基類,而不是QAbstractSocket抽象套接字類。
一 QTcpServer
#ifndef VXMAINWINDOW_H
#define VXMAINWINDOW_H
#define VXMAINWINDOW_H
#include <QWidget>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
class QPushButton;
class QTextEdit;
class QTextEdit;
class CVxMainWindow : public QWidget
{
Q_OBJECT
{
Q_OBJECT
public:
CVxMainWindow(QWidget *parent = NULL);
~CVxMainWindow();
protected:
void resizeEvent(QResizeEvent *);
private slots:
void Btn_ListenClickedSlot();
void Btn_StopListenClickedSlot();
void newConnectionSlot();
void dataReceived();
private:
QTcpServer *m_pServer;
QTcpSocket *m_pSocket;
CVxMainWindow(QWidget *parent = NULL);
~CVxMainWindow();
protected:
void resizeEvent(QResizeEvent *);
private slots:
void Btn_ListenClickedSlot();
void Btn_StopListenClickedSlot();
void newConnectionSlot();
void dataReceived();
private:
QTcpServer *m_pServer;
QTcpSocket *m_pSocket;
QPushButton *m_pBtn_Listen;
QPushButton *m_pBtn_StopListen;
QTextEdit *m_pEdt_Info;
};
QPushButton *m_pBtn_StopListen;
QTextEdit *m_pEdt_Info;
};
#endif // VXMAINWINDOW_H
#include "VxMainWindow.h"
#include <QtGui/QtGui>
CVxMainWindow::CVxMainWindow(QWidget *parent)
: QWidget(parent)
{
m_pBtn_Listen = new QPushButton(QObject::tr("開始監聽"), this);
m_pBtn_StopListen = new QPushButton(QObject::tr("停止監聽"), this);
m_pEdt_Info = new QTextEdit(this);
m_pServer = new QTcpServer(this);
connect(m_pBtn_Listen, SIGNAL(clicked()), this, SLOT(Btn_ListenClickedSlot()));
connect(m_pBtn_StopListen, SIGNAL(clicked()), this, SLOT(Btn_StopListenClickedSlot()));
connect(m_pServer, SIGNAL(newConnection()), this, SLOT(newConnectionSlot()));
}
: QWidget(parent)
{
m_pBtn_Listen = new QPushButton(QObject::tr("開始監聽"), this);
m_pBtn_StopListen = new QPushButton(QObject::tr("停止監聽"), this);
m_pEdt_Info = new QTextEdit(this);
m_pServer = new QTcpServer(this);
connect(m_pBtn_Listen, SIGNAL(clicked()), this, SLOT(Btn_ListenClickedSlot()));
connect(m_pBtn_StopListen, SIGNAL(clicked()), this, SLOT(Btn_StopListenClickedSlot()));
connect(m_pServer, SIGNAL(newConnection()), this, SLOT(newConnectionSlot()));
}
CVxMainWindow::~CVxMainWindow()
{
{
}
void CVxMainWindow::resizeEvent(QResizeEvent *)
{
m_pBtn_Listen->setGeometry(10, 5, 80, 20);
m_pBtn_StopListen->setGeometry(100, 5, 80, 20);
m_pEdt_Info->setGeometry(0, 30, width(), height() - 30);
}
{
m_pBtn_Listen->setGeometry(10, 5, 80, 20);
m_pBtn_StopListen->setGeometry(100, 5, 80, 20);
m_pEdt_Info->setGeometry(0, 30, width(), height() - 30);
}
void CVxMainWindow::Btn_ListenClickedSlot()
{
if (!m_pServer->isListening())
{
if (m_pServer->listen(QHostAddress::Any, 8080))
{
m_pEdt_Info->append(QObject::tr("打開監聽端口成功!"));
}
else
{
m_pEdt_Info->append(QObject::tr("打開監聽端口失敗!"));
}
}
else
{
m_pEdt_Info->append(QObject::tr("正在監聽中...!"));
}
}
{
if (!m_pServer->isListening())
{
if (m_pServer->listen(QHostAddress::Any, 8080))
{
m_pEdt_Info->append(QObject::tr("打開監聽端口成功!"));
}
else
{
m_pEdt_Info->append(QObject::tr("打開監聽端口失敗!"));
}
}
else
{
m_pEdt_Info->append(QObject::tr("正在監聽中...!"));
}
}
void CVxMainWindow::Btn_StopListenClickedSlot()
{
if (m_pServer->isListening())
{
m_pServer->close();
m_pEdt_Info->append(QObject::tr("停止監聽!"));
}
}
{
if (m_pServer->isListening())
{
m_pServer->close();
m_pEdt_Info->append(QObject::tr("停止監聽!"));
}
}
void CVxMainWindow::newConnectionSlot()
{
m_pEdt_Info->append(QObject::tr("有新客戶端連接到服務器"));
m_pSocket = m_pServer->nextPendingConnection();
connect(m_pSocket, SIGNAL(disconnected()), m_pSocket, SLOT(deleteLater()));
connect(m_pSocket, SIGNAL(readyRead()),this, SLOT(dataReceived()));
{
m_pEdt_Info->append(QObject::tr("有新客戶端連接到服務器"));
m_pSocket = m_pServer->nextPendingConnection();
connect(m_pSocket, SIGNAL(disconnected()), m_pSocket, SLOT(deleteLater()));
connect(m_pSocket, SIGNAL(readyRead()),this, SLOT(dataReceived()));
int length = 0;
QString vMsgStr = QObject::tr("Welcome");
if((length=m_pSocket->write(vMsgStr.toLatin1(),vMsgStr.length()))!=vMsgStr.length())
{
QString vMsgStr = QObject::tr("Welcome");
if((length=m_pSocket->write(vMsgStr.toLatin1(),vMsgStr.length()))!=vMsgStr.length())
{
}
}
}
void CVxMainWindow::dataReceived()
{
while(m_pSocket->bytesAvailable())
{
QByteArray vTemp;
vTemp = m_pSocket->readLine();
{
while(m_pSocket->bytesAvailable())
{
QByteArray vTemp;
vTemp = m_pSocket->readLine();
QString vTempStr(vTemp);
m_pEdt_Info->append(vTempStr);
m_pEdt_Info->append(vTempStr);
int length = 0;
QString vMsgStr = QObject::tr("回復:") + vTempStr;
if((length=m_pSocket->write(vMsgStr.toLatin1(),vMsgStr.length()))!=vMsgStr.length())
{
QString vMsgStr = QObject::tr("回復:") + vTempStr;
if((length=m_pSocket->write(vMsgStr.toLatin1(),vMsgStr.length()))!=vMsgStr.length())
{
}
}
}
}
}
二 QTcpSocket
#ifndef VXMAINWINDOW_H
#define VXMAINWINDOW_H
#define VXMAINWINDOW_H
#include <QWidget>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QHostAddress>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QHostAddress>
class QPushButton;
class QTextEdit;
class QLineEdit;
class QTextEdit;
class QLineEdit;
class CVxMainWindow : public QWidget
{
Q_OBJECT
{
Q_OBJECT
public:
CVxMainWindow(QWidget *parent = NULL);
~CVxMainWindow();
protected:
void resizeEvent(QResizeEvent *);
private slots:
void Btn_ConnectClickedSlot();
void Btn_DisConnectClickedSlot();
void Btn_SendClickedSlot();
void connectedSlot();
void disconnectedSlot();
void dataReceived();
void displayError(QAbstractSocket::SocketError);
private:
QTcpSocket *m_pSocket;
QHostAddress m_HostAddress;
CVxMainWindow(QWidget *parent = NULL);
~CVxMainWindow();
protected:
void resizeEvent(QResizeEvent *);
private slots:
void Btn_ConnectClickedSlot();
void Btn_DisConnectClickedSlot();
void Btn_SendClickedSlot();
void connectedSlot();
void disconnectedSlot();
void dataReceived();
void displayError(QAbstractSocket::SocketError);
private:
QTcpSocket *m_pSocket;
QHostAddress m_HostAddress;
QPushButton *m_pBtn_Connect;
QPushButton *m_pBtn_DisConnect;
QTextEdit *m_pEdt_Info;
QLineEdit *m_pEdt_Send;
QPushButton *m_pBtn_Send;
};
QPushButton *m_pBtn_DisConnect;
QTextEdit *m_pEdt_Info;
QLineEdit *m_pEdt_Send;
QPushButton *m_pBtn_Send;
};
#endif // VXMAINWINDOW_H
#include "VxMainWindow.h"
#include <QtGui/QtGui>
CVxMainWindow::CVxMainWindow(QWidget *parent)
: QWidget(parent)
{
m_pBtn_Connect = new QPushButton(QObject::tr("連接服務器"), this);
m_pBtn_DisConnect = new QPushButton(QObject::tr("斷開連接"), this);
m_pEdt_Send = new QLineEdit(this);
m_pBtn_Send = new QPushButton(QObject::tr("發送"), this);
m_pEdt_Info = new QTextEdit(this);
m_pSocket = new QTcpSocket(this);
: QWidget(parent)
{
m_pBtn_Connect = new QPushButton(QObject::tr("連接服務器"), this);
m_pBtn_DisConnect = new QPushButton(QObject::tr("斷開連接"), this);
m_pEdt_Send = new QLineEdit(this);
m_pBtn_Send = new QPushButton(QObject::tr("發送"), this);
m_pEdt_Info = new QTextEdit(this);
m_pSocket = new QTcpSocket(this);
connect(m_pBtn_Connect, SIGNAL(clicked()), this, SLOT(Btn_ConnectClickedSlot()));
connect(m_pBtn_DisConnect, SIGNAL(clicked()), this, SLOT(Btn_DisConnectClickedSlot()));
connect(m_pBtn_Send, SIGNAL(clicked()), this, SLOT(Btn_SendClickedSlot()));
connect(m_pSocket, SIGNAL(connected()), this, SLOT(connectedSlot()));
connect(m_pSocket, SIGNAL(disconnected()), this, SLOT(disconnectedSlot()));
connect(m_pSocket, SIGNAL(readyRead()),this, SLOT(dataReceived()));
connect(m_pSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
}
connect(m_pBtn_DisConnect, SIGNAL(clicked()), this, SLOT(Btn_DisConnectClickedSlot()));
connect(m_pBtn_Send, SIGNAL(clicked()), this, SLOT(Btn_SendClickedSlot()));
connect(m_pSocket, SIGNAL(connected()), this, SLOT(connectedSlot()));
connect(m_pSocket, SIGNAL(disconnected()), this, SLOT(disconnectedSlot()));
connect(m_pSocket, SIGNAL(readyRead()),this, SLOT(dataReceived()));
connect(m_pSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
}
CVxMainWindow::~CVxMainWindow()
{
{
}
void CVxMainWindow::resizeEvent(QResizeEvent *)
{
m_pBtn_Connect->setGeometry(10, 5, 80, 20);
m_pBtn_DisConnect->setGeometry(100, 5, 80, 20);
m_pEdt_Send->setGeometry(10, 30, 150, 20);
m_pBtn_Send->setGeometry(170, 30, 80, 20);
m_pEdt_Info->setGeometry(0, 60, width(), height() - 60);
}
{
m_pBtn_Connect->setGeometry(10, 5, 80, 20);
m_pBtn_DisConnect->setGeometry(100, 5, 80, 20);
m_pEdt_Send->setGeometry(10, 30, 150, 20);
m_pBtn_Send->setGeometry(170, 30, 80, 20);
m_pEdt_Info->setGeometry(0, 60, width(), height() - 60);
}
void CVxMainWindow::Btn_ConnectClickedSlot()
{
m_HostAddress.setAddress(QObject::tr("127.0.0.1"));
m_pSocket->connectToHost(m_HostAddress, 8080);
}
{
m_HostAddress.setAddress(QObject::tr("127.0.0.1"));
m_pSocket->connectToHost(m_HostAddress, 8080);
}
void CVxMainWindow::Btn_DisConnectClickedSlot()
{
m_pSocket->disconnectFromHost();
}
{
m_pSocket->disconnectFromHost();
}
void CVxMainWindow::Btn_SendClickedSlot()
{
int length = 0;
QString vMsgStr = m_pEdt_Send->text();
if((length = m_pSocket->write(vMsgStr.toLatin1(),vMsgStr.length())) != vMsgStr.length())
{
m_pEdt_Info->append(QObject::tr("發送信息失敗:") + vMsgStr);
}
}
{
int length = 0;
QString vMsgStr = m_pEdt_Send->text();
if((length = m_pSocket->write(vMsgStr.toLatin1(),vMsgStr.length())) != vMsgStr.length())
{
m_pEdt_Info->append(QObject::tr("發送信息失敗:") + vMsgStr);
}
}
void CVxMainWindow::connectedSlot()
{
m_pEdt_Info->append(QObject::tr("成功連接到服務器!"));
}
{
m_pEdt_Info->append(QObject::tr("成功連接到服務器!"));
}
void CVxMainWindow::disconnectedSlot()
{
m_pEdt_Info->append(QObject::tr("斷開與服務器的連接!"));
}
{
m_pEdt_Info->append(QObject::tr("斷開與服務器的連接!"));
}
void CVxMainWindow::dataReceived()
{
while(m_pSocket->bytesAvailable())
{
QString vTemp;
vTemp = m_pSocket->readLine();
m_pEdt_Info->append(vTemp);
}
}
{
while(m_pSocket->bytesAvailable())
{
QString vTemp;
vTemp = m_pSocket->readLine();
m_pEdt_Info->append(vTemp);
}
}
void CVxMainWindow::displayError(QAbstractSocket::SocketError)
{
{
}
以上代碼在發送和接受串中帶中文時會出現亂碼,下面提供另外的發送和接受方法:
1 發送:
void XXX()
{
// 用於暫存我們要發送的數據
QByteArray block;
// 使用數據流寫入數據
QDataStream out(&block,QIODevice::WriteOnly);
// 設置數據流的版本,客戶端和服務器端使用的版本要相同
out.setVersion(QDataStream::Qt_4_7);
out<<(quint16) 0;
{
// 用於暫存我們要發送的數據
QByteArray block;
// 使用數據流寫入數據
QDataStream out(&block,QIODevice::WriteOnly);
// 設置數據流的版本,客戶端和服務器端使用的版本要相同
out.setVersion(QDataStream::Qt_4_7);
out<<(quint16) 0;
out<<QObject::tr("您好啊!");
out.device()->seek(0);
out<<(quint16)(block.size() - sizeof(quint16));
m_pSocket->write(block);
}
out.device()->seek(0);
out<<(quint16)(block.size() - sizeof(quint16));
m_pSocket->write(block);
}
2 接受:
void CVxMainWindow::dataReceived()
{
QString vTempStr;
quint16 blockSize = 0;
{
QString vTempStr;
quint16 blockSize = 0;
QDataStream in(m_pSocket);
// 設置數據流版本,這里要和服務器端相同
in.setVersion(QDataStream::Qt_4_7);
// 如果是剛開始接收數據
if(blockSize == 0)
{
//判斷接收的數據是否有兩字節,也就是文件的大小信息
//如果有則保存到blockSize變量中,沒有則返回,繼續接收數據
if(m_pSocket->bytesAvailable() < (int)sizeof(quint16)) return;
in >> blockSize;
}
// 如果沒有得到全部的數據,則返回,繼續接收數據
if(m_pSocket->bytesAvailable() < blockSize) return;
in >> vTempStr;
m_pEdt_Info->append(vTempStr);
}
// 設置數據流版本,這里要和服務器端相同
in.setVersion(QDataStream::Qt_4_7);
// 如果是剛開始接收數據
if(blockSize == 0)
{
//判斷接收的數據是否有兩字節,也就是文件的大小信息
//如果有則保存到blockSize變量中,沒有則返回,繼續接收數據
if(m_pSocket->bytesAvailable() < (int)sizeof(quint16)) return;
in >> blockSize;
}
// 如果沒有得到全部的數據,則返回,繼續接收數據
if(m_pSocket->bytesAvailable() < blockSize) return;
in >> vTempStr;
m_pEdt_Info->append(vTempStr);
}
