TCP
TCP是一个基于流的协议。对于应用程序,数据表现为一个长长的流,而不是一个大大的平面文件。基于TCP的高层协议通常是基于行的或者基于块的。
●、基于行的协议把数据作为一行文本进行传输,每行都以一个换行符结尾。
●、基于块的协议把数据作为二进制块进行传输,每块是由一个size大小字段和紧跟它的一个size字节的数据组成。
QTcpSocket通过器父类QAbstractSocket继承了QIODevice,因此他可以通过使用QTextStream和QDataStream来进行读取和写入。
QTcpServer类在服务器端处理来自TCP客户端连接数据,需要注意的是,该类直接继承于QObject基类,而不是QAbstractSocket抽象套接字类。
一 QTcpServer
#ifndef VXMAINWINDOW_H
#define VXMAINWINDOW_H
#include <QWidget>
#include
<QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
class QPushButton;
class QTextEdit;
class CVxMainWindow : public QWidget
{
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;
QPushButton *m_pBtn_Listen;
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()));
}
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);
}
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("正在监听中...!"));
}
}
void CVxMainWindow::Btn_StopListenClickedSlot()
{
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()));
int length = 0;
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();
QString
vTempStr(vTemp);
m_pEdt_Info->append(vTempStr);
int length = 0;
QString vMsgStr =
QObject::tr("回复:") +
vTempStr;
if((length=m_pSocket->write(vMsgStr.toLatin1(),vMsgStr.length()))!=vMsgStr.length())
{
}
}
}
二 QTcpSocket
#ifndef VXMAINWINDOW_H
#define VXMAINWINDOW_H
#include <QWidget>
#include
<QtNetwork/QTcpSocket>
#include <QtNetwork/QHostAddress>
class QPushButton;
class QTextEdit;
class QLineEdit;
class CVxMainWindow : public QWidget
{
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;
QPushButton *m_pBtn_Connect;
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);
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)));
}
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);
}
void
CVxMainWindow::Btn_ConnectClickedSlot()
{
m_HostAddress.setAddress(QObject::tr("127.0.0.1"));
m_pSocket->connectToHost(m_HostAddress,
8080);
}
void
CVxMainWindow::Btn_DisConnectClickedSlot()
{
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);
}
}
void
CVxMainWindow::connectedSlot()
{
m_pEdt_Info->append(QObject::tr("成功连接到服务器!"));
}
void
CVxMainWindow::disconnectedSlot()
{
m_pEdt_Info->append(QObject::tr("断开与服务器的连接!"));
}
void
CVxMainWindow::dataReceived()
{
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;
out<<QObject::tr("您好啊!");
out.device()->seek(0);
out<<(quint16)(block.size()
- sizeof(quint16));
m_pSocket->write(block);
}
2 接受:
void CVxMainWindow::dataReceived()
{
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);
}