2016-10-17 70 views
0

下面的代碼在C和Qt C++中有TCP服務器。我的問題是我使用TCP來保證可靠性,但它有數據丟失(不是數據包)。在我的主代碼中,如果我運行tcp客戶端發送數據,TCP服務器只接收一個數據包。如果我在每個數據包傳輸之間向客戶端添加sleep(1);,則TCP服務器接收數據。客戶端和服務器都在同一臺計算機上運行。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[] = "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; 
} 

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:00 $ 321 $二四七五四$ 321 $ 13132 $ 1 $ 98 $ 0 $ 5.1 $ 0 $ 3C $ $ 64 1 $ $ 96 4D $ 3E8 $ $ 38 2 $ $ 46直流$ 4 $ 3 $ F6 $ E6 $ $ 17 0 $ E6 $ D3 $ 1 $ 0 $ E6 $ D3 $ 996 *** 124b00068c158f $ 321 $五二七一二三〇四$ 13.212779 $ 0 $ö$ 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 $ 997 *** 124b00068c158f $ 321 $五千二百七十一萬二千三百○四$ 13.212779 $ 0 $ö$ 0 $ 0 $ B4 $ 1 $ 0 $ 3 $ 0 $ 0 $ 0 $ 0 $ $ 11 0 $ 7 $ 0 $ 1 $ FE $ F1 $ aaa9fffffffffd80 $ 2132 b00 $ 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 $ë 6 $ D3 $ 1 $ 0 $ E6 $ D3 $ 998 *** 124b00068c158f $ 321 $五二七一二三〇四$ 13.212779 $ 0 $ö$ 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 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 $ 999產品*** 124b00068c158f $ 321 $五二七一二三○四$ 13.212779 $ 0 $ö$ 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 $」 斷開

問題1 與原始消息相比,它錯過了(14字節)發送數據的「1 $ 0 $ e6 $ d3 $ 2 $ 0 $」部分。缺少信息的原因是什麼?如何修復TCP服務器接收完整數據的代碼。

問題2 當我在我使用相同的碼作爲大的代碼和TCP服務器的一部分開頭提到接收分組,當我把睡眠(1)的每個分組傳輸之間(否則它只接收第一個數據包)。它的原因是什麼以及如何解決它?

我觀察到Wireshark上的數據包傳輸是所有的TCP數據包都發送成功,但好像接收部分有問題。

我使用Ubuntu 15.04,內核3.19.0-69泛型,gcc版本4.9.2

+1

哇,很多代碼。請出示您的[MCVE]。 –

回答

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

if (n < 0){ 

您只是檢查write()沒有返回負值,表明有錯誤。

但是,套接字的write()不保證寫入所有請求的字節。在套接字上的write()可能會返回一個正值,這裏的值小於msgLength,表示寫入的請求字節數少於所請求的字節數。詳細記錄在write()的手冊頁中。

您忽略了這種可能性,這就是您丟失數據的可能原因。在這種情況下,由你決定要做什麼。通常的做法是簡單地返回並嘗試寫入剩餘的字節(也可能不會完整寫入)。

同樣,從套接字讀取時,不能保證發件人寫入套接字的所有內容都將以一個大寫讀取。您需要確認您的閱讀器已經閱讀了所有需要閱讀的內容,並且如果閱讀器需要更多數據,請繼續從套接字讀取,直到收到它。

+0

是的,我在wireshark上看到發送的數據包丟失。謝謝。 – sven

1

readAll只是讀取提供給當前時刻的所有數據。

相關問題