服务器QTcpSocket“;“休息”;太早了,客户没有';我没有收到所有的数据,知道为什么吗?
我编写了一个客户机/服务器TCP/IP程序,在服务器生成一个更大的文件之前,它工作得很好。在这一点上,它破裂了,不是所有的时间,但往往足以使它成为一个真正的问题。我用TCP/IP编写了一个小版本,它重现了这个问题,我觉得这个问题给人留下了深刻的印象 我尝试了各种方法来解决这个问题,但我不太确定下一步该怎么办服务器QTcpSocket“;“休息”;太早了,客户没有';我没有收到所有的数据,知道为什么吗?,qt,tcp,client-server,Qt,Tcp,Client Server,我编写了一个客户机/服务器TCP/IP程序,在服务器生成一个更大的文件之前,它工作得很好。在这一点上,它破裂了,不是所有的时间,但往往足以使它成为一个真正的问题。我用TCP/IP编写了一个小版本,它重现了这个问题,我觉得这个问题给人留下了深刻的印象 我尝试了各种方法来解决这个问题,但我不太确定下一步该怎么办 /* * Test showing that at times a socket close() + exit(0) prevents all the * data from reach
/*
* Test showing that at times a socket close() + exit(0) prevents all the
* data from reaching the client.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <QCoreApplication>
#include <QByteArray>
#include <QFile>
#include <QTcpSocket>
#include <QTcpServer>
#include <QHostAddress>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
void
client()
{
QHostAddress a("192.168.2.1");
int port = 4004;
QTcpSocket socket;
socket.connectToHost(a, port);
if(socket.waitForConnected())
{
// if we get here then we can just copy the output of the child to Apache2
// the wait will flush all the writes as necessary
if(!socket.waitForReadyRead())
{
fprintf(stderr, "error: waitForReadyRead() timed out.\n");
exit(1);
}
// buffer somewhere to check the output validity
FILE *f = fopen("/tmp/out.html", "w");
if(f == NULL)
{
fprintf(stderr, "error: could not create /tmp/out.html file.\n");
exit(1);
}
for(;;)
{
char buf[64 * 1024];
qint64 r(socket.read(buf, sizeof(buf)));
if(r > 0)
{
fwrite(buf, r, 1, f);
}
else if(r == -1)
{
fprintf(stderr, "error: an error occured while read()'ing from the socket.\n");
break;
}
else if(r == 0)
{
// no more data (since our socket is blocking this really
// only happens when no more data is available)
break;
}
}
fclose(f);
return;
}
fprintf(stderr, "error: client could not connect to server.\n");
exit(1);
}
void
server()
{
QTcpServer s;
QHostAddress a("0.0.0.0");
if(!s.listen(a, 4004))
{
fprintf(stderr, "error: server is not able to listen, port 4004 not available?\n");
exit(1);
}
pid_t pid(0);
for(;;)
{
if(pid > 0)
{
int status;
if(waitpid(pid, &status, WNOHANG) == pid)
{
pid = 0;
}
}
s.waitForNewConnection(-1);
if(pid > 0)
{
int status;
if(waitpid(pid, &status, 0) == pid)
{
pid = 0;
}
}
QTcpSocket *socket(s.nextPendingConnection());
pid = fork();
if(pid == 0)
{
// this makes it work a bit better but we still have the
// early disconnection
int optval(1);
socklen_t optlen(sizeof(optval));
if(setsockopt(socket->socketDescriptor(), SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) {
fprintf(stderr, "warning: could not mark the new connection with keepalive flag.\n");
}
// we are the child, write in the socket and close it
QFile f("example.html");
f.open(QIODevice::ReadOnly);
QByteArray buffer(f.readAll());
f.close();
socket->write(buffer);
// the sleep makes it slow, but it doesn't make any difference
//sleep(2);
socket->flush();
// extra sleep/flush don't make any difference
//sleep(1);
//socket->flush();
//sleep(1);
//socket->flush();
// the read doesn't seem to fix anything
socket->waitForReadyRead();
socket->disconnectFromHost();
delete socket;
exit(0);
}
else {
if(pid == -1) {
fprintf(stderr, "error: could not create child process to handle the socket.\n");
}
socket->close();
}
}
}
int
main(int argc, char *argv[])
{
if(argc == 1)
{
client();
}
else if(strcmp(argv[1], "-s") == 0)
{
server();
}
else
{
printf("Usage: %s [-s]\n", argv[0]);
exit(1);
}
exit(0);
}
还有我的shell脚本:
#!/bin/sh
for g in a b c d e f g h i j k l m n o p q r s t u v w x y z
do
for f in 1 2 3 4 5 6 7 8 9 10
do
BUILD/tcp-bug
if [ `stat -c %s /tmp/out.html` -ne 41812 ]
then
echo "Error occured! Iteration: $g - $f"
ls -l /tmp/out.html
exit 1
fi
done
done
请注意,脚本需要一个41812字节的文件,该文件位于下一页的.tar.gz中(您也可以创建自己的example.html文件,即服务器读取并发送给客户端的文件):
我可以推荐一个链接,指向我在Qt服务器和客户端上给出的答案吗?对客户机/服务器在永久循环中工作正常。在我的例子中,子项(用fork创建)进入
if(pid==0)
块。如果你仔细看,我有一个出口(0)
在该块的末尾。这一机制之所以重要,主要有两个原因:安全性,因此每个孩子都在自己的进程中(每个孩子都有自己的数据库连接)和内存管理(每个孩子使用的内存或多或少,有时数量巨大……因此我们希望退出孩子,而不是让服务器永远增长。)我敢打赌,如果没有这个退出()打电话就行了。实际上我的答案上已经有了;)@亚历克西斯·威尔克你解决过这个问题吗?我正在为同样的问题而挣扎。将插槽连接到ReadyRead()会获取服务器发送的所有数据,但在询问轮询(WaitForBytesWrite)不支持的问题时,会尝试获取所有可用字节。@Rachel,是的,我解决了问题,不是的,我无法使Qt实现工作。如果您愿意的话,我在我的开源项目中有这样的代码,请查找tcp_client_server.cpp/h并直接使用这些代码。如果需要,还可以使用UDP客户端/服务器。
#!/bin/sh
for g in a b c d e f g h i j k l m n o p q r s t u v w x y z
do
for f in 1 2 3 4 5 6 7 8 9 10
do
BUILD/tcp-bug
if [ `stat -c %s /tmp/out.html` -ne 41812 ]
then
echo "Error occured! Iteration: $g - $f"
ls -l /tmp/out.html
exit 1
fi
done
done