分类: C/C++

 



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);

}