#ifndef TCP_THREAD_H
#define TCP_THREAD_H
#include
#include
#include
#define MAX_SEND_MSG_LEN 68
struct _loop_buf {
int num_of_unit; // Number of data units
int unit_size;
int rhead; // Head for read
int whead; // Head for write
void *buf_head;
};
class TcpThread : public QThread
{
Q_OBJECT
private:
QTcpServer *tcpServer;
QTcpSocket *socket;
QString ipAddress;
quint16 destinationPort;
int Flag;
bool quit;
struct _loop_buf loop_buf;
void run() Q_DECL_OVERRIDE;
void processMessage(char *msg);
int init_loop_buf(struct _loop_buf *loop_buf, int num_of_unit, int unit_size);
void reset_loop_buf(struct _loop_buf *loop_buf);
void release_loop_buf(struct _loop_buf *loop_buf);
int read_data_from_loop_buf(struct _loop_buf *loop_buf, void *data_unit);
QByteArray bytes;
QByteArray byteGet;
public:
TcpThread(QString ipAddress, quint16 destinationPort, QObject *parent = 0);
~TcpThread();
int addMessage(void *data_unit);
signals:
void error(int socketError, const QString &message);
public slots:
void finishWork(void);
void newConnectionSlot();
void dataReceived();
};
#endif // TCP_THREAD_H
.h文件
#if defined(_MSC_VER) && (_MSC_VER >= 1600)
#pragma execution_character_set("utf-8")
#endif
//#define MAX_SEND_MSG_LEN = 68
#include "TcpThread.h"
#include "widget.h"
#include <QDebug>
TcpThread::TcpThread(QString ipAddress, quint16 destinationPort, QObject *parent)
: QThread(parent), quit(false)
{
this->ipAddress = ipAddress;
this->destinationPort = destinationPort;
// Initialize loop buffer
// Max length of messages to be sent is 68 bytes.
if (init_loop_buf(&loop_buf, 128000, MAX_SEND_MSG_LEN) != 0) {
qDebug() << "Can't initialize loop buffer.";
return;
}
}
TcpThread::~TcpThread()
{
// Wait for the end of the thread.
quit = true;
wait();
}
void TcpThread::run()
{
//
// At here, it is in the execution context of newly created thread.
// So, it is better to define or create objects here.
// Or, following error may occurred:
// QObject: Cannot create children for a parent that is in a different thread
//
char *msg;//, *sendMsg;
int conn_timeout = 30000;
int read_timeout = 5000;
int write_timeout = 5000;
int bytesToRead, readBytes;
int bytesToWrite, writeBytes;
int ret;
int gotMessageHead = 0;
int toGetNewMessage = 0;
//msg = (char *)calloc(65536 + 128, 1);
msg = (char *)calloc(MAX_SEND_MSG_LEN, 1);
if (msg == NULL) {
qDebug() << "Can't allocate memory.";
return;
}
tcpServer = new QTcpServer();
socket = new QTcpSocket();
//connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newConnectionSlot()), Qt::DirectConnection);
if (!tcpServer->isListening())
{
qDebug() << ipAddress;
//if (tcpServer->listen(QHostAddress::QHostAddress(ipAddress), 16512))
if (tcpServer->listen(QHostAddress::Any, 16512))
{
//m_pEdt_Info->append(QObject::tr("打开监听端口成功!111"));
qDebug()<< QObject::tr("打开监听端口成功!111");
socket = tcpServer->nextPendingConnection();
// //connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
connect(socket, SIGNAL(readyRead()),this, SLOT(dataReceived()));
}
else
{
//m_pEdt_Info->append(QObject::tr("打开监听端口失败!"));
qDebug()<< QObject::tr("打开监听端口失败!11");
}
}
else
{
//m_pEdt_Info->append(QObject::tr("正在监听中...!"));
qDebug()<< QObject::tr("正在监听中...!");
}
qDebug() << "Connected to" << ipAddress;
// reset read variables
readBytes = 0;
bytesToRead = 4;
gotMessageHead = 0;
// reset write variables
writeBytes = 0;
toGetNewMessage = 1;
}
void TcpThread::processMessage(char *msg)
{
qDebug() << "Receive message:" << *(unsigned short *)msg <<
". Length:" << *(unsigned short *)(msg + 2);
}
void TcpThread::finishWork(void)
{
quit = true;
}
int TcpThread::init_loop_buf(struct _loop_buf *loop_buf, int num_of_unit, int unit_size)
{
unsigned long long total_size;
total_size = (unsigned long long)unit_size * (unsigned long long)num_of_unit;
if (total_size > 0x7fffffff) {
printf("Memory to be allocated is too large.\n");
return -1;
}
if (num_of_unit > 0x7ffffff0) {
printf("Buffer size can't exceed 0x7ffffff0.\n");
return -1;
}
loop_buf->num_of_unit = num_of_unit;
loop_buf->unit_size = unit_size;
loop_buf->rhead = 0;
loop_buf->whead = 0;
loop_buf->buf_head = malloc(total_size);
if (loop_buf->buf_head == NULL) {
printf("Can't allocate memory for the loop buffer.\n");
return -1;
}
return 0;
}
// Be careful to call this function. You must make sure that
// nobody is using the loop buffer pointed by 'loop_buf',
// or error may occur.
void TcpThread::reset_loop_buf(struct _loop_buf *loop_buf)
{
loop_buf->rhead = 0;
loop_buf->whead = 0;
}
void TcpThread::release_loop_buf(struct _loop_buf *loop_buf)
{
free(loop_buf->buf_head);
}
//
// Return value:
// 0: Success.
// -1: The loop buffer is NULL.
//
int TcpThread::read_data_from_loop_buf(struct _loop_buf *loop_buf, void *data_unit)
{
if (loop_buf->rhead == loop_buf->whead) {
// The buffer is null.
return -1;
}
//
// Do your work here, you can read data from the loop buffer.
// Following is just an example.
//
// Note:
// Must copy the data out, or the content of the data unit may be
// overwritten.
//
memcpy(data_unit, (char *)loop_buf->buf_head + loop_buf->rhead * loop_buf->unit_size, (size_t)loop_buf->unit_size);
if (loop_buf->rhead == (loop_buf->num_of_unit - 1)) {
loop_buf->rhead = 0;
} else {
loop_buf->rhead++;
}
return 0;
}
//
// --- IMPORTANT ---
// There is no mutex to avoid race condition in the function's implementation.
// So, to call this function from only one code source.
//
//Return value:
// 0: Success.
// -1: The loop buffer is full.
//
int TcpThread::addMessage(void *data_unit)
{
int tmp_whead = 0;
tmp_whead = loop_buf.whead + 1;
if (tmp_whead >= loop_buf.num_of_unit) {
tmp_whead = 0;
}
if (tmp_whead == loop_buf.rhead) {
// The buffer is full.
return -1;
}
//
// Do your work here, you can write data to the loop buffer.
// Following is just an example.
//
memcpy((char *)loop_buf.buf_head + loop_buf.whead * loop_buf.unit_size, data_unit, (size_t)loop_buf.unit_size);
loop_buf.whead = tmp_whead;
return 0;
}
void TcpThread::newConnectionSlot()
{
//m_pEdt_Info->append(QObject::tr("有新客户端连接到服务器"));
socket = tcpServer->nextPendingConnection();
connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
connect(socket, SIGNAL(readyRead()),this, SLOT(dataReceived()));
}
void TcpThread::dataReceived()
{
bytes = socket->readAll();
qDebug() << bytes.length() << bytes.size();
//if (bytes.size()=0) waitfo
if (byteGet.size()!=0){
byteGet.append(bytes.left(68-byteGet.size()));
bytes.remove(0,68-byteGet.size());
qDebug() << byteGet.length() << bytes.size();
}
for (;bytes.size()>=68;){
byteGet = bytes.left(68);
//m_pEdt_Info->append(byteGet.toHex());
bytes.remove(0,68);
qDebug() << byteGet.length() << bytes.size();
}
if (bytes.size()>0&&bytes.size()<68){
byteGet = bytes;
bytes.remove(0,byteGet.size());
qDebug() << byteGet.toHex();
qDebug() << byteGet.length() << bytes.size();
//bytes = m_pSocket->readLine();
//m_pServer->close();
}
}
.cpp文件
线程中接收数据,使用信号机制可不可以啊?
我用connect(socket, SIGNAL(readyRead()),this, SLOT(dataReceived()));
发现Slot里面定义的接收数据并未调用到。为什么,是this的问题,还是不应该这样使用信号机制。或者还有别的什么好方法吗,麻烦各位大神热点,感激
贴一下你的socket所属的类(包括.h和.cpp)
手册中原文:
This signal is emitted once every time new data is available for reading from the device. It will only be emitted again once new data is available, such as when a new payload of network data has arrived on your network socket, or when a new block of data has been appended to your device.
readyRead() is not emitted recursively; if you reenter the event loop or call waitForReadyRead() inside a slot connected to the readyRead() signal, the signal will not be reemitted (although waitForReadyRead() may still return true).
Note for developers implementing classes derived from QIODevice: you should always emit readyRead() when new data has arrived (do not emit it only because there's data still to be read in your buffers). Do not emit readyRead() in other conditions.
你看一下tcpsocket的状态是否是error啊。
手册中是这么说的:
This signal is emitted once every time new data is available for reading from the device. It will only be emitted again once new data is available, such as when a new payload of network data has arrived on your network socket, or when a new block of data has been appended to your device.
意思是readyread信号在且只在有新数据到达时才会被发射。需要注意的是readyread并不是递归的(readyRead() is not emitted recursively)。
所以在收到新数据的时候只要你没有解除链接,那么这个就一直存在,除非socket状态编程error或者closingstatus等特殊状态。