TCPスティッキーパケットの問題と解決策

目次

1.TCPスティッキーパケットの複製

2.解決策


1.TCPスティッキーパケットの複製

ソケット通信によるデータの送受信は関係ありません。read()関数は、データが何度送信されても​​、できるだけ多くのデータを受信します。つまり、read()とwrite()の実行回数が異なる場合があります。

たとえば、write()は文字「abc」が送信されるたびに3回繰り返し実行され、ターゲットマシンのread()は3回受信し、毎回「abc」を受信する場合があります。また、2回受信する場合もあります。 1回目「abcab」と「cabc」を2回目に受信します。文字列「abcabcabc」を1回受信することもできます。

クライアントに一度に1人の学生の学生IDを送信させ、サーバーに学生の名前、住所、成績などの情報を返してもらいたいとします。このとき、問題が発生し、サーバーは学生IDを識別できません。たとえば、最初に1を送信し、2回目に3を送信する場合、サーバーはそれを13として処理する可能性があり、返された情報は明らかに間違っています。

これはデータの「スティッキーパケット」の問題です。クライアントから送信された複数のデータパケットは1つのデータパケットとして受信されます。これはデータのボーダレスとも呼ばれます。read()関数は、データの開始フラグと終了フラグを認識しません。データパケット(実際には、開始マークまたは終了マークもありません)であり、それらを連続データストリームとしてのみ扱います。

次のコードは、スティッキーパケットの問題を示しています。クライアントが99の長さのデータをサーバーに送信するたびに、サーバーは一度にまとめられた多数のデータを受信する場合があります。

サーバ: 

/*================================================================
 *   Copyright (C) 2021 baichao All rights reserved.
 *
 *   文件名称:service1.c
 *   创 建 者:baichao
 *   创建日期:2021年01月25日
 *   描    述:
 *
 ================================================================*/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(){
    //创建套接字
    int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    //将套接字和IP、端口绑定
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));  //每个字节都用0填充
    serv_addr.sin_family = AF_INET;  //使用IPv4地址
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址
    serv_addr.sin_port = htons(11230);  //端口
    bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

    //进入监听状态,等待用户发起请求
    listen(serv_sock, SOMAXCONN);


    //接收客户端请求
    struct sockaddr_in clnt_addr;
    socklen_t clnt_addr_size = sizeof(clnt_addr);

    int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
    int count = 0;
    while(1)
    {

        //sleep(5);
        char str[102400];
        int readNum = read(clnt_sock,str,sizeof(str));
        if(readNum <= 0)
            continue;
        std::cout<<"第"<<++count<<"次读取数据长度为:"<<readNum<<std::endl;
        // write(clnt_sock, , sizeof(str));

    }
    close(clnt_sock);
    close(serv_sock);
    return 0;
}

クライアント:

/*================================================================
 *   Copyright (C) 2021 baichao All rights reserved.
 *
 *   文件名称:client1.cpp
 *   创 建 者:baichao
 *   创建日期:2021年01月25日
 *   描    述:
 *
 ================================================================*/

#include<iostream>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int main(){

    int serv_sock = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(11230);

    connect(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

    char context[100] = {0};
    for(int i = 0; i < sizeof(context)/sizeof(context[0]); ++i)
        context[i] = '1';
    while(1)
    {

        write(serv_sock,context,sizeof(context)-1);
    }
    close(serv_sock);

    return 0;
}

演算結果:

 データが読み取られてから48回目以降、スティッキーパケットの問題が発生していることがわかります。

2.解決策

2.1。サーバーは最初にデータの長さを送信し、次にデータを送信します

2.2。「\ n」などの各データの後に終了文字を設定します

おすすめ

転載: blog.csdn.net/weixin_40179091/article/details/113139670