TCP 服务器未正确接收数据
TCP Server doesn't receive data correctly
下面的代码在 C 中有一个 TCP 客户端,在 Qt C++ 中有一个 TCP 服务器。我的问题是我使用 TCP 来提高可靠性,但它有数据丢失(不是数据包)。在我的主要代码中,如果我 运行 tcp 客户端发送数据,TCP 服务器只收到一个数据包。如果我在每次数据包传输之间向客户端添加 sleep(1);
,则 TCP 服务器会接收数据。客户端和服务器 运行 在同一台计算机上。
为了简化问题并且不能在此处放置太大的代码,我有以下执行速度更快的代码,但它丢失了数据包的最后 10-15 个字节。
TCP C 客户端
main.c
#include "socket_handler.h" //I didn't put the all includes here
#define PORT 22208
//tcp server
int main(void)
{
int sockfd;
uint32_t senderAddress = 2130706433; //127.0.0.1
if( connect_to_server_w_uint( &sockfd, senderAddress, PORT ) < 0 ){
printf("error at line 454\n");
exit(1);
}
char data[] = "124b00068c158f1712304.212779[=10=]$O[=10=][=10=]$b4[=10=][=10=][=10=][=10=][=10=][=10=][=10=]$fe$f1$aaa9fffffffffd8032b00$eb460b5e16-02-22 03:01:00[=10=]00-00-00 00:00:0017541132[=10=].1[=10=]cde8$dc$f6$e6[=10=]$e6$d3[=10=]$e6$d3[=10=]£";
char buffer[512];
int i=0;
for(i=0; i<1000; i++){
bzero(buffer, 512);
sprintf(buffer, "%d***%s -----",i,data);
send_data_to_server(&sockfd, buffer, strlen(data) +1 );
printf("[%d]: data is sent\n", i);
}
close_connection(&sockfd);
return 0;
}
socket_handler.c
int connect_to_server(int *sockfd , struct in_addr senderAddress, uint16_t destPort){
struct sockaddr_in serv_addr;
*sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (*sockfd < 0)
//error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr = senderAddress;
serv_addr.sin_port = htons(destPort);
if (connect( *sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0){
printf("connection error line 1413\n");
close( *sockfd );
return -1;
}
return 0;
}
int connect_to_server_w_uint(int *sockfd, uint32_t senderAddress, uint16_t destPort){
struct sockaddr_in serv_addr;
*sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (*sockfd < 0){
printf("ERROR opening socket");
close(*sockfd);
return -1;
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(senderAddress);
serv_addr.sin_port = htons(destPort);
if (connect(*sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
{
printf("ERROR connecting");
close(*sockfd);
return -1;
}
return 0;
}
int send_data_to_server(int *sockfd, char *message, uint16_t msgLength){
int n = write(*sockfd, message, msgLength);
if (n < 0){
printf("ERROR writing to socket");
return -1;
}
return 0;
}
int close_connection(int *sockfd){
close( *sockfd );
return 0;
}
Qt C++ TCP 服务器
MainWindow.cpp
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void ParseThePacket(QByteArray data);
private:
Ui::MainWindow *ui;
Server *server;
};
Client.h
class Client : public QObject
{
Q_OBJECT
public:
explicit Client(QObject *parent = 0);
public slots:
bool connectToHost(QString host);
bool writeData(QByteArray data);
private:
QTcpSocket *socket;
};
Server.cpp
Server::Server(QObject *parent) : QObject(parent)
{
server = new QTcpServer(this);
connect(server, SIGNAL(newConnection()), this, SLOT(newConnection()));
if( server->listen(QHostAddress::Any, PORT) ){
qDebug() << "tcp server started!";
}else{
qDebug() << "tcp server couldn't start listening";
}
}
void Server::newConnection()
{
qDebug() << "new connection";
while (server->hasPendingConnections())
{
socket = server->nextPendingConnection();
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
}
}
void Server::disconnected()
{
qDebug() << "disconnected";
socket->deleteLater();
}
void Server::readyRead()
{
qDebug() << "readyRead";
QByteArray buffer = socket->readAll();
emit dataReceived(buffer);
}
这是 TCP 服务器的示例输出(qDebug() 输出的结尾):
00:00:0017541132[=16=].1[=16=]cde8$dc$f6$e6[=16=]$e6$d3[=16=]$e6$d36***124b00068c158f1712304.212779[=16=]$O[=16=][=16=]$b4[=16=][=16=][=16=][=16=][=16=][=16=][=16=]$fe$f1$aaa9fffffffffd8032b00$eb460b5e16-02-22
03:01:00[=16=]00-00-00
00:00:0017541132[=16=].1[=16=]cde8$dc$f6$e6[=16=]$e6$d3[=16=]$e6$d37***124b00068c158f1712304.212779[=16=]$O[=16=][=16=]$b4[=16=][=16=][=16=][=16=][=16=][=16=][=16=]$fe$f1$aaa9fffffffffd8032b00$eb460b5e16-02-22
03:01:00[=16=]00-00-00
00:00:0017541132[=16=].1[=16=]cde8$dc$f6$e6[=16=]$e6$d3[=16=]$e6$d38***124b00068c158f1712304.212779[=16=]$O[=16=][=16=]$b4[=16=][=16=][=16=][=16=][=16=][=16=][=16=]$fe$f1$aaa9fffffffffd8032b00$eb460b5e16-02-22
03:01:00[=16=]00-00-00
00:00:0017541132[=16=].1[=16=]cde8$dc$f6$e6[=16=]$e6$d3[=16=]$e6$d39***124b00068c158f1712304.212779[=16=]$O[=16=][=16=]$b4[=16=][=16=][=16=][=16=][=16=][=16=][=16=]$fe$f1$aaa9fffffffffd8032b00$eb460b5e16-02-22
03:01:00[=16=]00-00-00
00:00:0017541132[=16=].1[=16=]cde8$dc$f6$e6[=16=]$e6$d3[=16=]$e6$d3$"
disconnected
问题 1
与原始消息相比,它丢失了(14 字节)发送数据的“1$0$e6$d3$2$0£”部分。消息丢失的原因是什么? TCP服务器接收到完整数据的代码如何修复
问题 2
正如我在开头提到的,我使用相同的代码作为大型代码的一部分,当我在每个数据包传输之间放置 sleep(1) 时,TCP 服务器接收数据包(否则它接收仅第一个数据包)。它的原因是什么以及如何解决它?
我在Wireshark上观察数据包传输,所有TCP数据包发送成功,但接收部分似乎有问题。
我正在使用 Ubuntu 15.04,内核 3.19.0-69-generic,gcc 版本 4.9.2
readAll 只读取当前时刻的所有可用数据。
int n = write(*sockfd, message, msgLength);
if (n < 0){
您只是在检查 write()
没有 return 负值,这表明有错误。
但是,write()
到套接字并不能保证所有请求的字节都将被写入。套接字上的 write()
可能 return 为正值,小于此处的 msgLength
,表示已写入的字节数少于请求的字节数。这在 write()
的手册页中有详细记录。
您忽略了这种可能性,这可能是您丢失数据的原因。在这种情况下,由您决定要做什么。通常的方法是简单地返回并尝试写入剩余的字节(同样,可能不会全部写入)。
类似地,当从套接字读取时,您不能保证发送方写入套接字的所有内容都会在一个 gulp 中读取。由您来验证您的 reader 是否已读取所有要读取的内容,如果 reader 需要更多数据,请继续从套接字读取直到接收到它。
下面的代码在 C 中有一个 TCP 客户端,在 Qt C++ 中有一个 TCP 服务器。我的问题是我使用 TCP 来提高可靠性,但它有数据丢失(不是数据包)。在我的主要代码中,如果我 运行 tcp 客户端发送数据,TCP 服务器只收到一个数据包。如果我在每次数据包传输之间向客户端添加 sleep(1);
,则 TCP 服务器会接收数据。客户端和服务器 运行 在同一台计算机上。
为了简化问题并且不能在此处放置太大的代码,我有以下执行速度更快的代码,但它丢失了数据包的最后 10-15 个字节。
TCP C 客户端
main.c
#include "socket_handler.h" //I didn't put the all includes here
#define PORT 22208
//tcp server
int main(void)
{
int sockfd;
uint32_t senderAddress = 2130706433; //127.0.0.1
if( connect_to_server_w_uint( &sockfd, senderAddress, PORT ) < 0 ){
printf("error at line 454\n");
exit(1);
}
char data[] = "124b00068c158f1712304.212779[=10=]$O[=10=][=10=]$b4[=10=][=10=][=10=][=10=][=10=][=10=][=10=]$fe$f1$aaa9fffffffffd8032b00$eb460b5e16-02-22 03:01:00[=10=]00-00-00 00:00:0017541132[=10=].1[=10=]cde8$dc$f6$e6[=10=]$e6$d3[=10=]$e6$d3[=10=]£";
char buffer[512];
int i=0;
for(i=0; i<1000; i++){
bzero(buffer, 512);
sprintf(buffer, "%d***%s -----",i,data);
send_data_to_server(&sockfd, buffer, strlen(data) +1 );
printf("[%d]: data is sent\n", i);
}
close_connection(&sockfd);
return 0;
}
socket_handler.c
int connect_to_server(int *sockfd , struct in_addr senderAddress, uint16_t destPort){
struct sockaddr_in serv_addr;
*sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (*sockfd < 0)
//error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr = senderAddress;
serv_addr.sin_port = htons(destPort);
if (connect( *sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0){
printf("connection error line 1413\n");
close( *sockfd );
return -1;
}
return 0;
}
int connect_to_server_w_uint(int *sockfd, uint32_t senderAddress, uint16_t destPort){
struct sockaddr_in serv_addr;
*sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (*sockfd < 0){
printf("ERROR opening socket");
close(*sockfd);
return -1;
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(senderAddress);
serv_addr.sin_port = htons(destPort);
if (connect(*sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
{
printf("ERROR connecting");
close(*sockfd);
return -1;
}
return 0;
}
int send_data_to_server(int *sockfd, char *message, uint16_t msgLength){
int n = write(*sockfd, message, msgLength);
if (n < 0){
printf("ERROR writing to socket");
return -1;
}
return 0;
}
int close_connection(int *sockfd){
close( *sockfd );
return 0;
}
Qt C++ TCP 服务器
MainWindow.cpp
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void ParseThePacket(QByteArray data);
private:
Ui::MainWindow *ui;
Server *server;
};
Client.h
class Client : public QObject
{
Q_OBJECT
public:
explicit Client(QObject *parent = 0);
public slots:
bool connectToHost(QString host);
bool writeData(QByteArray data);
private:
QTcpSocket *socket;
};
Server.cpp
Server::Server(QObject *parent) : QObject(parent)
{
server = new QTcpServer(this);
connect(server, SIGNAL(newConnection()), this, SLOT(newConnection()));
if( server->listen(QHostAddress::Any, PORT) ){
qDebug() << "tcp server started!";
}else{
qDebug() << "tcp server couldn't start listening";
}
}
void Server::newConnection()
{
qDebug() << "new connection";
while (server->hasPendingConnections())
{
socket = server->nextPendingConnection();
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
}
}
void Server::disconnected()
{
qDebug() << "disconnected";
socket->deleteLater();
}
void Server::readyRead()
{
qDebug() << "readyRead";
QByteArray buffer = socket->readAll();
emit dataReceived(buffer);
}
这是 TCP 服务器的示例输出(qDebug() 输出的结尾):
00:00:0017541132[=16=].1[=16=]cde8$dc$f6$e6[=16=]$e6$d3[=16=]$e6$d36***124b00068c158f1712304.212779[=16=]$O[=16=][=16=]$b4[=16=][=16=][=16=][=16=][=16=][=16=][=16=]$fe$f1$aaa9fffffffffd8032b00$eb460b5e16-02-22 03:01:00[=16=]00-00-00 00:00:0017541132[=16=].1[=16=]cde8$dc$f6$e6[=16=]$e6$d3[=16=]$e6$d37***124b00068c158f1712304.212779[=16=]$O[=16=][=16=]$b4[=16=][=16=][=16=][=16=][=16=][=16=][=16=]$fe$f1$aaa9fffffffffd8032b00$eb460b5e16-02-22 03:01:00[=16=]00-00-00 00:00:0017541132[=16=].1[=16=]cde8$dc$f6$e6[=16=]$e6$d3[=16=]$e6$d38***124b00068c158f1712304.212779[=16=]$O[=16=][=16=]$b4[=16=][=16=][=16=][=16=][=16=][=16=][=16=]$fe$f1$aaa9fffffffffd8032b00$eb460b5e16-02-22 03:01:00[=16=]00-00-00 00:00:0017541132[=16=].1[=16=]cde8$dc$f6$e6[=16=]$e6$d3[=16=]$e6$d39***124b00068c158f1712304.212779[=16=]$O[=16=][=16=]$b4[=16=][=16=][=16=][=16=][=16=][=16=][=16=]$fe$f1$aaa9fffffffffd8032b00$eb460b5e16-02-22 03:01:00[=16=]00-00-00 00:00:0017541132[=16=].1[=16=]cde8$dc$f6$e6[=16=]$e6$d3[=16=]$e6$d3$" disconnected
问题 1 与原始消息相比,它丢失了(14 字节)发送数据的“1$0$e6$d3$2$0£”部分。消息丢失的原因是什么? TCP服务器接收到完整数据的代码如何修复
问题 2 正如我在开头提到的,我使用相同的代码作为大型代码的一部分,当我在每个数据包传输之间放置 sleep(1) 时,TCP 服务器接收数据包(否则它接收仅第一个数据包)。它的原因是什么以及如何解决它?
我在Wireshark上观察数据包传输,所有TCP数据包发送成功,但接收部分似乎有问题。
我正在使用 Ubuntu 15.04,内核 3.19.0-69-generic,gcc 版本 4.9.2
readAll 只读取当前时刻的所有可用数据。
int n = write(*sockfd, message, msgLength);
if (n < 0){
您只是在检查 write()
没有 return 负值,这表明有错误。
但是,write()
到套接字并不能保证所有请求的字节都将被写入。套接字上的 write()
可能 return 为正值,小于此处的 msgLength
,表示已写入的字节数少于请求的字节数。这在 write()
的手册页中有详细记录。
您忽略了这种可能性,这可能是您丢失数据的原因。在这种情况下,由您决定要做什么。通常的方法是简单地返回并尝试写入剩余的字节(同样,可能不会全部写入)。
类似地,当从套接字读取时,您不能保证发送方写入套接字的所有内容都会在一个 gulp 中读取。由您来验证您的 reader 是否已读取所有要读取的内容,如果 reader 需要更多数据,请继续从套接字读取直到接收到它。