我是Qt的新手,我有点挣扎。我正在尝试使用QTcpSocket从客户端向服务器发送字符串。
客户方:
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << name;
tSock->connectToHost(ipAddress, portNumb.toInt());
tSock->waitForConnected();
tSock->write(block); // block is not empty
tSock->flush();
服务器端:
void Server::readyRead()
{
QByteArray block;
QDataStream out(&block, QIODevice::ReadOnly);
out << tcpSocket->readAll();
QString name(block); // block is empty
players.insert(name, tcpSocket);
std::cout << "name: " << name.toStdString(); // TODO remove
}
在服务器端,程序在收到数据时输入readyRead()
,但是块为空,尽管在调用tSock->write(block)
时客户端块不为空...在哪里似乎是问题?我将不胜感激任何帮助。谢谢!
答案 0 :(得分:2)
修改:您的错误是您以 ReadOnly 模式打开out
数据流,但尝试写收到的信息字节数组:
void Server::readyRead()
{
QByteArray block;
QDataStream out(&block, QIODevice::ReadOnly); // !mistake, WriteOnly mode is needed
out << tcpSocket->readAll(); // this is write operation
//...
}
附加:请注意,Serialization mechanism of Qt Data Types在这种情况下很有用:
tSock->write(block); // this is write just a raw data of the block, not the "QByteArray"
您可以使用流操作直接将必要的Qt数据类型写入套接字,而无需转换为QByteArray
:
// Connect firstly
tSock->connectToHost(ipAddress, portNumb.toInt());
tSock->waitForConnected();
// Then open a data stream for the socket and write to it:
QDataStream out(tSock, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << name; // write string directly without a convertion to QByteArray
// Then you may
tSock->flush();
在客户端,然后在服务器端使用类似的流操作:
void Server::readyRead()
{
QString name;
QDataStream in(tcpSocket, QIODevice::ReadOnly /*or QIODevice::ReadWrite if necessary */);
in.setVersion(QDataStream::Qt_4_0);
in >> name; // read the string
//...
}
还可以读取/写入另一个Qt&lt; s / o设备:QFile,QSerialPort,QProcess,QBuffer和其他设备。
编辑2 :无法保证在readyRead
信号上您收到已发送的完整包裹。因此,请参阅下面的示例。
请注意,在实际案例中(当您在客户端 - 服务器通信中有多个不同的数据包,并且不知道您收到的几种可能的包时)通常存在使用更复杂的算法,因为通信中的readyRead事件可能会发生以下情况:
算法的变体(Qt 4 Fortune Client Example):
void Client::readFortune() // on readyRead
{
QDataStream in(tcpSocket);
in.setVersion(QDataStream::Qt_4_0);
if (blockSize == 0) {
if (tcpSocket->bytesAvailable() < (int)sizeof(quint16))
return;
in >> blockSize;
}
if (tcpSocket->bytesAvailable() < blockSize)
return;
QString nextFortune;
in >> nextFortune;
//...
}
Qt 4.0是Qt的旧版本,因此另见Qt 5.9 Fortune Client Example
答案 1 :(得分:0)
您的服务器似乎没有足够的时间从客户端写入数据。 请试试这个..
tcpsocket->waitForBytesWritten(1000);
答案 2 :(得分:0)
readyRead
代码错误地填写了block
。您还假设您将读取足够的数据来传达整个字符串。这绝不保证。当readyRead
触发它时,您知道的所有内容都至少要读取一个字节。 QDataStream
交易系统有助于此。
这将是一个正确的实施:
class Server : public QObject {
Q_OBJECT
QPointer<QTcpSocket> m_socket;
QDataStream m_in{m_socket.data(), &QIODevice::ReadOnly};
void onReadyRead();
public:
Server(QTcpSocket * socket, QObject * parent = {}) :
QObject(parent),
m_socket(socket)
{
connect(socket, &QIODevice::readyRead, this, &Server::onReadyRead);
}
}
void onReadyRead() {
while (true) { // must keep reading as long as names are available
QString name;
in >> name;
if (in.commitTransaction()) {
qDebug << name;
players.insert(name, &m_socket.data());
} else
break;
}
};