Форум программистов, компьютерный форум, киберфорум
C++: Сети
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.64/25: Рейтинг темы: голосов - 25, средняя оценка - 4.64
4 / 4 / 2
Регистрация: 13.11.2014
Сообщений: 108

Потеря части больших данных при приёме через recv

17.04.2023, 16:10. Показов 5485. Ответов 3

Студворк — интернет-сервис помощи студентам
Есть небольшой сервер на C++ кросплатформенный с поддержкой SSL (там собстно 2 порта ssl и без него), на неблокирующих сокетах epoll, который всё больше и больше разрастается. Разбирает себе HTTP заголовок, на точки входа, парсит json, что-то там добавляет в базу и т.д. и т.п.
Всё работает всё хорошо, НО теперь встала задача по приёму в POST'е тупо большого json'а. Он достаточно прост, вот пример:
JSON
1
2
3
4
5
6
7
8
9
10
{
"list_updates":
[
{
"ID_device": "1",
"New_GUID": "d3d5dd4c5ae64e688ce43939092ead21"
},
...
]
}
При этом в list_updates может себе спокойно находиться до 50 тысяч элементов, присылается такое не часто, но тем не менее. Ну так вот отсылаю 20 тысяч, в базу упорно залетает абсолютно рэндомное число, то 3 тысячи с хвостиком, то 5, то 17, а вполне мб, что и все.
Собственно проблема в самом заголовке, а сейчас опишу чего и как делал, что пробовал и т.д.
Элементарно while для recv на приёме:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
                vector<unsigned char> m_vRecvBuffer; //В этом буфере клиент будет хранить принятые данные
                int err;
                size_t total_buff = 0;
                    static char szBuffer[131072]; //4096 даём достаточно большой буфер, чтоб можно было побольше прочесть за раз, тогда у нас и циклов поменьше будет
                    errno = 0;
                    int nDataLength;
                    std::this_thread::sleep_for(std::chrono::milliseconds(10));
                    while ((nDataLength = ::recv(m_hSocket, szBuffer, 131072, 0)) > 0)
                    {
                        total_buff += nDataLength;
                        m_vRecvBuffer.resize(m_vRecvBuffer.size() + nDataLength);
                        memcpy(&m_vRecvBuffer[m_vRecvBuffer.size() - nDataLength], szBuffer, nDataLength); 
                        std::this_thread::sleep_for(std::chrono::milliseconds(100));
                    }
                    err = nDataLength; // total_buff;// nDataLength;
//...
//нуу и далее уже по коду вектор m_vRecvBuffer закидываю в строку для удобства и анализирую, m_vRecvBuffer тут чисто на будущее, вдруг ещё и файлы буду отсылать)
const std::string strInputString(m_vRecvBuffer.begin(), m_vRecvBuffer.end());
//ну и далее просто анализируем strInputString и чего-то там ещё и отдаём

На Windows всё работает отменно (код при этом собирается в VS 2019), хоть 100 тысяч записей отошли, всё нормально. А вот на CentOS7 собираю в g++ с стандартом C++14 языка и всё и трында(
У нас recv однажды получает 0 из стека TCP и всё мы отваливаемся и не дочитываем данные.
Порылся в интернете, аага, ok, у нас в стеке могут быть данные не сразу все, мб обрыв соединения или ещё что, т.е. прилетает себе вполне 0, а вот дальше идут ещё пакеты... и это не смотря на sleep_for который я прописывал, чтоб их дожидаться в стеке.... нуу ok, пробуем так
Пробовал уже и:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
                vector<unsigned char> m_vRecvBuffer; //В этом буфере клиент будет хранить принятые данные
                int err;
                size_t total_buff = 0;
                    static char szBuffer[131072]; //4096 даём достаточно большой буфер, чтоб можно было побольше прочесть за раз, тогда у нас и циклов поменьше будет
                    errno = 0;
                    int nDataLength;
                    int count_bad_read_recv = 0;
                    std::this_thread::sleep_for(std::chrono::milliseconds(10));
                    while (count_bad_read_recv <= 3) //на этот раз пробуем 3 раза почитать 0, авось чего прилетит
                    {
                        nDataLength = ::recv(m_hSocket, szBuffer, 131072, 0);
                        if (nDataLength > 0)
                        {
                            count_bad_read_recv = 0;
                            total_buff += nDataLength;
                            m_vRecvBuffer.resize(m_vRecvBuffer.size() + nDataLength);
                            memcpy(&m_vRecvBuffer[m_vRecvBuffer.size() - nDataLength], szBuffer, nDataLength); 
                        }
                        else
                        {
                            count_bad_read_recv++;
                        }
                        std::this_thread::sleep_for(std::chrono::milliseconds(100));
                        //Sleep(112);
                    }
                    err = nDataLength; // total_buff;// nDataLength;
//...
//нуу и далее уже по коду вектор m_vRecvBuffer закидываю в строку для удобства и анализирую, m_vRecvBuffer тут чисто на будущее, вдруг ещё и файлы буду отсылать)
const std::string strInputString(m_vRecvBuffer.begin(), m_vRecvBuffer.end());
//ну и далее просто анализируем strInputString и чего-то там ещё и отдаём

Но ниит( ето не прокатывает, пробуем и if (nDataLength >= 0) проставить и с таймера поиграться, всё тленн(
В процессе перепробовал уже всё что только можно я и MTU размеры пакета вычислял по самое не хочу и Content-Length анализировал, вообще чем только не страдал, вкорячивал и вовсе вот такую достаточно длинную и оптимизированную функцию для поиска списка кратных чисел размера пакета:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
/// <summary>
/// Функция по получению списка натуральных делитилей числа без остатка
/// </summary>
/// <param name="number_d">
/// Входящее положительное число
/// </param>
/// <returns>
/// Возвращает список чисел в виде вектора, например от числа 24 вернёт список: 1,2,4,8,3,6,12,24
/// </returns>
std::vector<int> GetNaturalDivisorsNumb(unsigned long long number_d)
{
    //сначала дадим немного проверок на мелкие числа и 0, что не сразу лезли в дебри, а ток для больших чисел
    if (number_d == 0)
    {
        std::vector<int> ret_vt = std::vector<int>(0);
        ret_vt.push_back(0);
        return ret_vt;
    }
    if (number_d == 1)
    {
        std::vector<int> ret_vt = std::vector<int>(0);
        ret_vt.push_back(1);
        return ret_vt;
    }
    if (number_d == 2)
    {
        std::vector<int> ret_vt = std::vector<int>(0);
        ret_vt.push_back(1);
        ret_vt.push_back(2);
        return ret_vt;
    }
    if (number_d == 3)
    {
        std::vector<int> ret_vt = std::vector<int>(0);
        ret_vt.push_back(1);
        ret_vt.push_back(3);
        return ret_vt;
    }
    if (number_d == 4)
    {
        std::vector<int> ret_vt = std::vector<int>(0);
        ret_vt.push_back(1);
        ret_vt.push_back(2);
        ret_vt.push_back(4);
        return ret_vt;
    }
 
    std::vector<int> ret_vali = std::vector<int>(0);
 
    unsigned long long Ostatok;
    unsigned long long Ostatok2;
    unsigned long long oldMn;
    unsigned long long ArrRez[3000] = { 0,1 };
    int option = 3;
    int Solutions(1);
    int y(1);
    int y2(1);
    unsigned long long mpz_Ostatok; //mpz_class
    unsigned long long mpz_Ostatok2;
    unsigned long long mpz_oldMn;
    unsigned long long mpz_ArrRez[100000] = { 0,1 };
 
    ret_vali.push_back(1);
    mpz_Ostatok = number_d;
 
    //чуть чуть простых чисел, чтоб не заморачиваться ещё и с алгоритмом их поиска, тем более, что нам их вполне хватит)
    std::vector<int> first1001 = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
        101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,
        179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,
        283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,
        419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,
        547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,
        661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,
        811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,
        947,953,967,971,977,983,991,997,1009,1013,1019,1021,1031,1033,1039,1049,1051,1061,1063,1069,
        1087,1091,1093,1097,1103,1109,1117,1123,1129,1151,1153,1163,1171,1181,1187,1193,1201,1213,1217,1223,
        1229,1231,1237,1249,1259,1277,1279,1283,1289,1291,1297,1301,1303,1307,1319,1321,1327,1361,1367,1373,
        1381,1399,1409,1423,1427,1429,1433,1439,1447,1451,1453,1459,1471,1481,1483,1487,1489,1493,1499,1511,
        1523,1531,1543,1549,1553,1559,1567,1571,1579,1583,1597,1601,1607,1609,1613,1619,1621,1627,1637,1657,
        1663,1667,1669,1693,1697,1699,1709,1721,1723,1733,1741,1747,1753,1759,1777,1783,1787,1789,1801,1811,
        1823,1831,1847,1861,1867,1871,1873,1877,1879,1889,1901,1907,1913,1931,1933,1949,1951,1973,1979,1987,
        1993,1997,1999,2003,2011,2017,2027,2029,2039,2053,2063,2069,2081,2083,2087,2089,2099,2111,2113,2129,
        2131,2137,2141,2143,2153,2161,2179,2203,2207,2213,2221,2237,2239,2243,2251,2267,2269,2273,2281,2287,
        2293,2297,2309,2311,2333,2339,2341,2347,2351,2357,2371,2377,2381,2383,2389,2393,2399,2411,2417,2423,
        2437,2441,2447,2459,2467,2473,2477,2503,2521,2531,2539,2543,2549,2551,2557,2579,2591,2593,2609,2617,
        2621,2633,2647,2657,2659,2663,2671,2677,2683,2687,2689,2693,2699,2707,2711,2713,2719,2729,2731,2741,
        2749,2753,2767,2777,2789,2791,2797,2801,2803,2819,2833,2837,2843,2851,2857,2861,2879,2887,2897,2903,
        2909,2917,2927,2939,2953,2957,2963,2969,2971,2999,3001,3011,3019,3023,3037,3041,3049,3061,3067,3079,
        3083,3089,3109,3119,3121,3137,3163,3167,3169,3181,3187,3191,3203,3209,3217,3221,3229,3251,3253,3257,
        3259,3271,3299,3301,3307,3313,3319,3323,3329,3331,3343,3347,3359,3361,3371,3373,3389,3391,3407,3413,
        3433,3449,3457,3461,3463,3467,3469,3491,3499,3511,3517,3527,3529,3533,3539,3541,3547,3557,3559,3571 };
 
    //std::vector<std::thread> thr(8);
    int arr[] = { 0,1,7,11, 13, 17, 19, 23, 29 };
    if (std::find(first1001.begin(), first1001.end(), number_d) != first1001.end())
    {
        if (mpz_Ostatok > 18446744073709551615) {
            mpz_Ostatok2 = sqrt(mpz_Ostatok);
            unsigned long long mpz_Mn = (2); //mpz_class
            unsigned long long mpz_oldMn = -1; //mpz_class
            while (mpz_Mn <= 30) {
                if (mpz_Ostatok % mpz_Mn == 0) { mpz_Mn++; }  //проверка на делимость //mpz_divisible_p(mpz_Ostatok.get_mpz_t(), mpz_Mn.get_mpz_t())
                else {
                    mpz_Ostatok = mpz_Ostatok / mpz_Mn;
                    mpz_Ostatok2 = sqrt(mpz_Ostatok);
 
                    if (option == 3) {//проверка на выбранную опцию
                        if (mpz_oldMn != mpz_Mn) {
                            for (y = 1; y <= Solutions; y++) {
                                mpz_ArrRez[Solutions + y] = mpz_ArrRez[y] * mpz_Mn;
                                //std::cout << mpz_ArrRez[Solutions + y] << std::endl;
                                ret_vali.push_back(mpz_ArrRez[Solutions + y]);
                            }
                            Solutions = Solutions + y - 1;
                        }
                        else {
                            for (y2 = 1; y2 < y; y2++) {
                                mpz_ArrRez[Solutions + y2] = mpz_ArrRez[Solutions - y + 1 + y2] * mpz_Mn;
                                //std::cout << mpz_ArrRez[Solutions + y2] << std::endl;
                                ret_vali.push_back(mpz_ArrRez[Solutions + y2]);
                            }
                            Solutions = Solutions + y2 - 1;
                        }
                    }
                    else if (mpz_oldMn != mpz_Mn || option != 2)
                    {
                        Solutions++;
                        //std::cout << mpz_Mn << std::endl;
                        ret_vali.push_back(mpz_Mn);
                    } //или
                    mpz_oldMn = mpz_Mn;
                }
            }
            //for (int i = 1; i <= 8; i++) thr[i - 1] = std::thread(Func2, arr[i]);
    //#pragma omp parallel for
            //for (int i = 1; i <= 8; i++) thr[i - 1].join();
#pragma omp parallel for
            for (int i = 1; i <= 8; i++)
            {
                unsigned long long mpz_Ch = (1); //mpz_class
                unsigned long long mpz_Mn = 30 * mpz_Ch + arr[i]; //mpz_class
                while (mpz_Mn <= mpz_Ostatok2) {
                    if (mpz_Ostatok % mpz_Mn == 0) { mpz_Ch++; mpz_Mn = 30 * mpz_Ch + arr[i]; }//проверка на делимость mpz_divisible_p(mpz_Ostatok.get_mpz_t(), mpz_Mn.get_mpz_t())
                    else {
                        //EnterCriticalSection(&cs);//критическая секция
                        mpz_Ostatok = mpz_Ostatok / mpz_Mn;
                        mpz_Ostatok2 = sqrt(mpz_Ostatok);
                        if (option == 3) {//проверка на выбранную опцию
                            if (mpz_oldMn != mpz_Mn) {
                                for (y = 1; y <= Solutions; y++) {
                                    mpz_ArrRez[Solutions + y] = mpz_ArrRez[y] * mpz_Mn;
                                    //std::cout << mpz_ArrRez[Solutions + y] << std::endl;
                                    ret_vali.push_back(mpz_ArrRez[Solutions + y]);
                                }
                                Solutions = Solutions + y - 1;
                            }
                            else {
                                for (y2 = 1; y2 < y; y2++) {
                                    mpz_ArrRez[Solutions + y2] = mpz_ArrRez[Solutions - y + 1 + y2] * mpz_Mn;
                                    //std::cout << mpz_ArrRez[Solutions + y2] << std::endl;
                                    ret_vali.push_back(mpz_ArrRez[Solutions + y2]);
                                }
                                Solutions = Solutions + y2 - 1;
                            }
                        }
                        else if (mpz_oldMn != mpz_Mn || option != 2)
                        {
                            Solutions++;
                            //std::cout << mpz_Mn << std::endl;
                            ret_vali.push_back(mpz_Mn);
                        } //или
                        mpz_oldMn = mpz_Mn;
                        //LeaveCriticalSection(&cs);//критическая секция
                    }
                }
            }
 
            if (mpz_Ostatok > 1) {//проверяем остаток
                if (option == 3) {
                    if (mpz_oldMn != mpz_Ostatok) {
                        for (y = 1; y <= Solutions; y++) {
                            mpz_ArrRez[Solutions + y] = mpz_ArrRez[y] * mpz_Ostatok;
                            //std::cout << mpz_ArrRez[Solutions + y] << std::endl;
                            ret_vali.push_back(mpz_ArrRez[Solutions + y]);
                        }
                        Solutions = Solutions + y - 1;
                    }
                    else {
                        for (y2 = 1; y2 < y; y2++) {
                            mpz_ArrRez[Solutions + y2] = mpz_ArrRez[Solutions - y + 1 + y2] * mpz_Ostatok;
                            //std::cout << mpz_ArrRez[Solutions + y2] << std::endl;
                            ret_vali.push_back(mpz_ArrRez[Solutions + y2]);
                        }
                        Solutions = Solutions + y2 - 1;
                    }
                }
                else
                {
                    //std::cout << mpz_Ostatok << std::endl;
                    ret_vali.push_back(mpz_Ostatok);
                    Solutions++;
                }
            }
        }
        else {
            Ostatok = mpz_Ostatok; // .get_ui();
            Ostatok2 = (unsigned long long)sqrt(Ostatok);
            unsigned long long Mn = (2);
            unsigned long long oldMn = -1;
            while (Mn <= 30) {
                if (Ostatok % Mn == 0) {//проверка на делимость
                    Ostatok = Ostatok / Mn;
                    Ostatok2 = (unsigned long long)sqrt(Ostatok);
 
                    if (option == 3) {//проверка на выбранную опцию
                        if (oldMn != Mn) {
                            for (y = 1; y <= Solutions; y++) {
                                ArrRez[Solutions + y] = ArrRez[y] * Mn;
                                //std::cout << ArrRez[Solutions + y] << std::endl;
                                ret_vali.push_back(ArrRez[Solutions + y]);
                            }
                            Solutions = Solutions + y - 1;
                        }
                        else {
                            for (y2 = 1; y2 < y; y2++) {
                                ArrRez[Solutions + y2] = ArrRez[Solutions - y + 1 + y2] * Mn;
                                //std::cout << ArrRez[Solutions + y2] << std::endl;
                                ret_vali.push_back(ArrRez[Solutions + y2]);
                            }
                            Solutions = Solutions + y2 - 1;
                        }
                    }
                    else if (oldMn != Mn || option != 2)
                    {
                        Solutions++;
                        //std::cout << Mn << std::endl;
                        ret_vali.push_back(Mn);
                    } //или
                    oldMn = Mn;
                }
                else { Mn++; }
            }
            //for (int i = 1; i <= 8; i++) thr[i - 1] = std::thread(Func, arr[i]);
    //#pragma omp parallel for
            //for (int i = 1; i <= 8; i++) thr[i - 1].join();
#pragma omp parallel for
            for (int i = 1; i <= 8; i++)
            {
                unsigned long long Ch = (1);
                unsigned long long Mn = 30 * Ch + arr[i];
                while (Mn <= Ostatok2) {
                    if (Ostatok % Mn == 0) {
                        //EnterCriticalSection(&cs);//критическая секция
                        Ostatok = Ostatok / Mn;
                        Ostatok2 = (unsigned long long)sqrt(Ostatok);
                        if (option == 3) {
                            if (oldMn != Mn) {
                                for (y = 1; y <= Solutions; y++) {
                                    ArrRez[Solutions + y] = ArrRez[y] * Mn;
                                    //std::cout << ArrRez[Solutions + y] << std::endl;
                                    ret_vali.push_back(ArrRez[Solutions + y]);
                                }
                                Solutions = Solutions + y - 1;
                            }
                            else {
                                for (y2 = 1; y2 < y; y2++) {
                                    ArrRez[Solutions + y2] = ArrRez[Solutions - y + 1 + y2] * Mn;
                                    //std::cout << ArrRez[Solutions + y2] << std::endl;
                                    ret_vali.push_back(ArrRez[Solutions + y2]);
                                }
                                Solutions = Solutions + y2 - 1;
                            }
                        }
                        else if (oldMn != Mn || option != 2)
                        {
                            Solutions++;
                            //std::cout << Mn << std::endl;
                            ret_vali.push_back(Mn);
                        } //или
                        oldMn = Mn;
                        //LeaveCriticalSection(&cs);//критическая секция
                    }
                    else
                    {
                        Ch++;
                        Mn = 30 * Ch + arr[i];
                    }
                }
            }
 
            if (Ostatok > 1) {//проверяем остаток
                if (option == 3) {
                    if (oldMn != Ostatok) {
                        for (y = 1; y <= Solutions; y++) {
                            ArrRez[Solutions + y] = ArrRez[y] * Ostatok;
                            std::cout << ArrRez[Solutions + y] << std::endl;
                        }
                        Solutions = Solutions + y - 1;
                    }
                    else {
                        for (y2 = 1; y2 < y; y2++) {
                            ArrRez[Solutions + y2] = ArrRez[Solutions - y + 1 + y2] * Ostatok;
                            //std::cout << ArrRez[Solutions + y2] << std::endl;
                            ret_vali.push_back(ArrRez[Solutions + y2]);
                        }
                        Solutions = Solutions + y2 - 1;
                    }
                }
                else
                {
                    //std::cout << Ostatok << std::endl;
                    ret_vali.push_back(Ostatok);
                    Solutions++;
                }
            }
        }
    }
    else
    {
        ret_vali.push_back(number_d);
    }
    //
    return ret_vali;
}

По которой вообще брал делители от 200 до 3000 и по их ряду определял пришёл нам оборванный пакет можно выходить с чтения, либо это что-то целостное и надо бы его ещё и проанализировать на Content-Length закончился ли размер.
По итогу и эту затею отмёл, т.к. я и вовсе не 0 ловил, а -1 и всё и происходил выход, так и не получив нормально всех данных. Т.е. там вообще имеем вариант с while (count_bad_read_recv <= 3) более предпочтительный.
Честно говоря это уже сводит меня с ума(
Я смотрел исходники nginx и libmicrohttpd, там вообще всё это дело гораздо проще, nginx мб ещё и живёт в своих простанствах имён и я чего не понял, но в libmicrohttpd элементарно тупо мой первый вариант и всё. Ну и что ему может не нравиться?
P.S. есть дефолтный проект, если что могу скинуть, но там как бы всё одно и тоже.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
17.04.2023, 16:10
Ответы с готовыми решениями:

Потеря части данных при отправке через TSocket
Доброго времени суток. Отправляю строку размером в 65536 символов(прямо перед отправкой вывожу в tmemo length(sign_db) чтобы проверить...

ARM11. Потеря данных при приеме UART-ом
Для передачи использую интерфейс UART, проц ARM11. Есть входной FIFO глубиной 32. Ставлю уровень заполнения FIFO и прерывание по этому...

Зависает при приёме больших данных
не могу разобраться что я делаю с потоком входящих данных не так, при входе большого колличества данных цикл уходит на второй круг и...

3
COM‐пропагандист
 Аватар для Замабувараев
936 / 785 / 149
Регистрация: 18.12.2014
Сообщений: 2,256
Записей в блоге: 4
18.04.2023, 08:00
Если вам recv вернула ноль, это значит что вы достигли конца потока байтов и другая сторона закрыла соединение. Единственное, что вам остаётся делать в этой ситуации — тоже закрыть сокет со своей стороны. Не пытайтесь читать байты из закрытого с той стороны сокета.

Добавлено через 11 минут
Цитата Сообщение от КиберСталкер21 Посмотреть сообщение
и Content-Length анализировал
Самый правильный вариант.
У метода POST всегда должно быть тело запроса.
1. Анализируем заголовки и ищем Content-Length. Если такого заголовка нет, то сразу отправляем ошибку 411 Length Required и закрываем соединение.
2. Выделаем память под массив размером, указанным в заголовке Content-Length (или место на диске, если размер длинный).
3. Делаем в цикле recv до тех пор пока не получим весь Content-Length.
0
4 / 4 / 2
Регистрация: 13.11.2014
Сообщений: 108
18.04.2023, 10:59  [ТС]
Мнение по поводу нуля я вычитал . Ни в коем случае не претендую на конечную истинность высказанных там выражений)
Просто есть мнение и я решил и его проверить в том числе.
Цитата Сообщение от Замабувараев Посмотреть сообщение
Самый правильный вариант.
У метода POST всегда должно быть тело запроса.
1. Анализируем заголовки и ищем Content-Length...
Вполне справедливо себе для HTTP протокола по которому мы и общаемся, но я бы всё-таки хотел оставить задатки и на НЕ HTTP протокол общения, просто на будущее мало ли чего мне понадобится, авось просто бинарниками какими буду плеваться и свалю на какой-то свой доморощенный modbus)
А посему анализ контента уже следует делать аж после приёма сообщения как такового и уже отдавать 411 или чего-то там ещё.
А вообще вот такая конструкция мне даже больше понравилась:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
                vector<unsigned char> m_vRecvBuffer; //В этом буфере клиент будет хранить принятые данные
                int err;
                size_t total_buff = 0;
                    static char szBuffer[67108860]; //даём достаточно тупо самый здоровый буфер
                    errno = 0;
                    int nDataLength;
                    std::this_thread::sleep_for(std::chrono::milliseconds(10));
                    while (true)
                    {
            //заранее получаем сколько у нас в стеке чего может храниться
            u_long nDataLength_arg = 0;
#ifdef WIN32
            ioctlsocket(m_hSocket, FIONREAD, &nDataLength_arg);
#else
            ioctl(m_hSocket, FIONREAD, &nDataLength_arg);
#endif
            //когда понимаем, что в стеке определённо что-то есть, тогда идём читать что там
            //не знаю почему, но иногда случалось так, что если читали 0, то recv тупо зависал
            //поэтому мне это поболее понравилось
            if (nDataLength_arg > 0)
            {
                nDataLength = ::recv(m_hSocket, szBuffer + total_buff, 67108860 - total_buff - 1, 0);
                if (nDataLength > 0)
                {
                    total_buff += nDataLength;
                }
                else
                {
                    break;
                }
            }
            else
            {
                break;
            }
                        std::this_thread::sleep_for(std::chrono::milliseconds(100));
                    }
            m_vRecvBuffer.resize(m_vRecvBuffer.size() + total_buff);
            memcpy(&m_vRecvBuffer[m_vRecvBuffer.size() - total_buff], szBuffer, total_buff);
                    err = nDataLength;
//...
//нуу и далее уже по коду вектор m_vRecvBuffer закидываю в строку для удобства и анализирую, m_vRecvBuffer тут чисто на будущее, вдруг ещё и файлы буду отсылать)
const std::string strInputString(m_vRecvBuffer.begin(), m_vRecvBuffer.end());
//ну и далее просто анализируем strInputString и чего-то там ещё и отдаём

И надо сказать это прям работает на 100% и можно закрывать тему)
НО либо я дурачок, либо лыжи не едут XD
Короче оказалось при большом количестве клиентов на которых я постоянно и тестировал у меня постоянно "вылетал стэк сокета", либо ещё что-то в этом роде. Но на одном всё работает стабильно. Да даже если 2 параллельно запустить. А пускаю третьего он уже ловит висяк на рэндомной отправке скажем в 900 записей, при этом они не записываются никак.
Закрываем всё это дело, Опять запускаю отправку теперь уже допустим на 4к записей, опять висяк, НО в это время на сервер приходят полные себе 900 записей предыдущих вместо 4к.
Опять закрываю, пускаю снова, снова висим, зато теперь приходят обрезанные 4к записей, вместо скажем 2к, что должны были отправиться, нуу и т.д. по кругу.
Короче я по ходу где-то накосячил с передачей сокета в класс клиента... они то там у меня ещё и map'ятся, короче эт мне теперь надолго разбираться) ...хотяя странно т.к. до этого просто делал с расчётом на постоянный MTU (а потом приобрёл кучу знаний о том на сколько он может быть различный то в мировой сети ) и вообще у 20 клиентов таких проблем не было.
В общем буду разбираться, но если у кого какие умные мысли возникнут, то welcome)

Добавлено через 3 минуты
хммм а ссылки на другой форум запрещены?)
нуу тогда мнение по поводу 0 я вычитал отсюда - ru_stackoverflow_com/ questions/ 442794/%D0%9A%D0%B0%D0%BA-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0% BB%D0%B8%D1%82%D1%8C-%D0%BA%D0%BE%D0%BD%D0%B5%D1%86-%D0%BF%D0%BE%D1%81%D1%8B%D0%BB%D0%BA%D0% B8-%D0%BF%D0%BE-%D1%81%D0%BE%D0%BA%D0%B5%D1%82%D0%B0%D0% BC
0
COM‐пропагандист
 Аватар для Замабувараев
936 / 785 / 149
Регистрация: 18.12.2014
Сообщений: 2,256
Записей в блоге: 4
18.04.2023, 14:49
Цитата Сообщение от Корпорация Микрософт
If the connection has been gracefully closed, the return value is zero.
Перевожу:
Если соединение было корректно закрыто, возвращаемое значение равно нулю.
https://learn.microsoft.com/en... nsock-recv

Пришло 0 байт = соединение закрыто. Это конец потока. Нет никакого смысла читать из потока, когда вы достигли конца. То же самое как нет никакого смысла читать из файла, когда вы достигли End Of File.
Всё что вам остаётся делать — закрыть сокет со своей стороны.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
18.04.2023, 14:49
Помогаю со студенческими работами здесь

Потеря части данных при извлечении поля из БД
Здравствуйте, Уважаемые! В сервлете я выполняю, например, следующий запрос ResultSet RS=statement.executeQuery('SELECT FIO, JOB FROM...

Ошибка при приеме данных через COM (Arduino-Xbee-PC)
Добрый день! Передаю данные с ардуины (Mega2560) через Xbee (EndDevice) на компьютер. К компу подключен второй Xbee (Coordinator). Каждый...

Дублирование данных при приеме файла через сокет
Добрый день господа, пишу приложение которое должно передавать файл по сети с возможностью докачки, программа работает, но почему то при...

Нечитаемый текст при приеме данных через COM PORT RS 232
Привет друзя, Я также программирую в студии RAD для Windows 10 -11 , и теперь я пытаюсь сделать программу, которая принимает данные и...

Обновление элемента label при приёме данных через serialport
Доброго времени суток! На форме имеются компоненты label и serialport. Через ком порт на комп передаю данные в виде переменной из одной...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Логарифм записывается как: (x-2)log(x^2+2) - означает логарифм (x^2+2) по основанию (x-2). Унарный минус обозначается как ! в-строка - входное арифметическое выражение в инфиксной(обычной). . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru