下面的代码在Qt C++中有一个C和TCP服务器的TCP客户端。我的问题是我正在使用TCP来保证可靠性,但是它有数据丢失(不是包)。在我的主代码中,如果我运行tcp客户机发送数据,tcp服务器只接收一个包。如果在每次数据包传输之间向客户机添加sleep(1);,则TCP服务器接收数据。客户机和服务器都在同一台计算机上运行。
为了简化这个问题,并且不能在这里放置太大的代码,我有下面的代码执行得更快,但是它会丢失包的最后10-15个字节。
TCP C客户端
主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[] = "124b00068c158f$321$52712304$13.212779$0$O$0$0$b4$1$0$3$0$0$0$0$11$0$7$0$1$fe$f1$aaa9fffffffffd80$2132b00$eb460b5e$1$1$2016-02-22 03:01:00$0000-00-00 00:00:00$321$24754$321$13132$1$98$0$5.1$0$3c$64$1$96$4d$3e8$38$2$46$dc$4$3$f6$e6$17$0$e6$d3$1$0$e6$d3$2$0£";
    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;
}

套接字处理程序.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+TCP服务器
主窗口.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;
};

客户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;

};

服务器.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:00:00$321$24754$321$13132$13132$1$1$98$0$5.1$0$0$24754$321$13132$1$1$$1$98$0$0$5.1$0$0$321$24754$321$321$13132$13132$1$1$98$98$0$0$5.1$0$0$5.1$0$3$0$0$3C$64$1$1$96$44D$4D$4D$3E8$38$2$2$46$2$46$4$3$3$F6$F6$6$6$6$17$0$E6$0$0$0$E6$$1$1$1$0 fffffd80$2132b00$eb460b5e$1$1$2016-02-22
03:01:00$0000-00-00
00:00:00:00$321$24754$321$13132$13132$1$1$98$0$5.1$0$$0$24754$321$13132$1$1$1$$98$0$5.1$0$0$$321$24754$321$$13132$$1$13113132$1$98$1$0$0$5.1$0$0$5.1$0$3$0$0$3C$64$1$1$96$44D$4D$4D$3E8$38$2$2$2$46$2$46$4$3$3$F6$F6$6$E6$17$0$E6$0$0$0$0$E6$1$1$1 fffffd80$2132b00$eb460b5e$1$1$2016-02-22
03:01:00$0000-00-00
00:00:00$321$24754$24754$321$13132$1$13132$1$1$98$0$5.1$0$0$$$0$321$24754$24754$321$13132$1$$1$13132$1$$1$321$24754$321$321$13132$13132$1$1$98$0$0$5.1$0$0$$$$$$$$$$$$24754$321$52712304$13.212779$0$0$0$0$0$$$131$13132$1$$1$$$$$1$98$98$0$0$5.1$0$0$5.1$0$0$0$0$$fffffffd80$2132b00$eb460b5e$1$1$2016-02-22
03:01:00$0000-00-00
00:00:00:00$321$24754$321$13132$13132$1$1$98$0$5.1$0$$0$24754$321$13132$1$1$1$$98$0$5.1$0$0$321$24754$321$321$13132$13132$1$$1$98$98$0$0$5.1$0$0$5.1$0$3$0$0$3C$64$1$$1$96$444D$4D$3E8$38$2$2$2$46$2$46$4$4$3$3$F6$F6$6$E6$17$0$E6$0$0$0$0$E6$$1$1 fffffd80$2132b00$eb460b5e$1$1$2016-02-22
03:01:00$0000-00-00
00:00:00$321$24754$321$13132$1$98$0$5.1$0$3C$64$1$96$4D$3E8$38$2$46$DC$4$3$F6$E6$17$0$E6$D3$1$0$E6$D3$”
断开的
问题1
与原始消息相比,它丢失了(14字节)发送数据的“1$0$E6$D3$2$0”部分。丢失信息的原因是什么?如何修复TCP服务器接收完整数据的代码。
问题2
正如我在开头提到的,我使用的代码与大代码的一部分相同,并且tcp服务器在每次数据包传输之间放置sleep(1)时接收数据包(否则它只接收第一个数据包)。原因是什么,如何解决?
我观察到wireshark上的数据包传输,所有的tcp数据包都成功发送,但是接收部分似乎有问题。
我使用的是ubuntu 15.04,内核3.19.0-69-generic,gcc版本4.9.2

最佳答案

int n = write(*sockfd, message, msgLength);

if (n < 0){

您只检查write()没有返回负值,表示有错误。
但是,对套接字的write()不能保证将写入所有请求的字节。套接字上的write()可能返回一个正值,这里小于msgLength,表示写入的字节数少于请求的字节数。这在write()的手册页中有详细的记录。
你忽略了这种可能性,这就是你丢失数据的可能原因。在这种情况下,你自己决定怎么做。通常的方法是简单地返回并尝试写入剩余的字节(同样,可能不会完整地写入这些字节)。
类似地,当从一个套接字读取数据时,并不能保证发送者写入套接字的所有内容都能一饮而尽。由您来验证您的读卡器是否已经读取了要读取的所有内容,如果读卡器需要更多数据,请继续从套接字读取,直到收到为止。

10-07 20:33