Форум программистов, компьютерный форум, киберфорум
Наши страницы
C++: Сети
Войти
Регистрация
Восстановить пароль
 
Izual
142 / 120 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
1

Send без реальной отправки

07.02.2018, 02:39. Просмотров 447. Ответов 10
Метки нет (Все метки)

Ситуация следующяя..

Есть Сервер и Клиент на WinSock, использую обычные Send и Recv. Когда всё нормально, то оба приложения работают нормально (сотни send / recv обрабатываются поочерёдно, т.е. сначала клиент шлёт send, потом 5 сек задержка, затем сервер шлёт send, естественно recv у тех, кто должен принимать).. но чуть какой косяк с коннектом, и тайминг перестаёт совпадать.. то происходят странные вещи..

Самая странная вещь, которую я даже понять не могу такая:
Отправляется файл, ввиду этого, очерёдности нету, т.к. у сервера только send, а у клиента соответственно только recv, так же с таймингом. (т.е. может доходить до сотен send, в зависимости от размера файла) Так вот, если в момент отправки файла клиент решает, что "не нужен мне никакой файл", то он меняет своё состояние recv, на минуту отдыха "sleep" (пока сервер не поймёт, что клиент не хочет докачивать файл), при этом не отключается от конекта с сервером.. Поидее у сервера при посылке очередного send, должен возникать SOCKET_ERROR, но его почему то не происходит, сервер как слал куски файла, так и продолжает, а return значение функции send продолжает возвращять значение, как будто send функция отработала как надо, и на другой стороне кто то принял recv.
Тестировал я это дело на локальной сети, ну т.е. взял два компа, соединил шнуром, выставил маску и айпишники, делая один из компов основным.

Может кто то может помочь с тем почему так происходит, и send не возвращяет SOCKET_ERROR.

Добавлено через 3 часа 44 минуты
P.S.
WinSock версии 2.2 (в WSAStartup передаётся MAKEWORD(2,2))
Библиотека: Ws2_32.lib
Протокол Ipv4. (по крайней мере его свойства я меняю для поднятия локалки)
Код смысла выкладывать не вижу, всё точно так же как и на MSDN.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.02.2018, 02:39
Ответы с готовыми решениями:

Можно ли реализовать программу для отправки смс без
Можно ли реализовать программу для отправки смс без запроса на сайт Сотовой...

Send в TCP
Каждый вызов функции send() на TCP клиенте передает отдельный пакет данных...

send(.);recv(.);
Привет всем. Хроника событий: В сети имеются компьютеры a-сервер,b-клиент....

send, recv и close
Что будет, если сервер пошлет данные на accept сокет и сразу же закроет этот...

Send() Post запрос
Вот у меня отправляется ответ клиенту (JS) static void ComeWebClients(SOCKET...

10
vxg
Модератор
3252 / 2052 / 323
Регистрация: 13.01.2012
Сообщений: 7,949
07.02.2018, 06:26 2
Izual, какой размер файла? Может система принимает его в буфер и ей без разницы что вы пока решили данные не забирать

Добавлено через 8 минут
Пошлите ему скажем 2 ГБ без приёма вот тогда наверняка вернёт ошибку но ничего хорошего в этой ситуации ждать не приходится - буфер на обоих концах будет забит данными которые вам не нужны - легче клиенту послать на сервер сообщение "горшочек не вари" или разорвать подключение
0
Izual
142 / 120 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
07.02.2018, 13:56  [ТС] 3
Файл не большой. У меня размер буффера 1024 байт, поэтому файлы выбираю соответственно 4-40кб. (небольшие, чтоб за минуту - две файл скачался) Естественно, send / recv идут по циклу, и код контролирует сколько положить в буффер, в зависимости от остатка файла.
Нет система тут не причём, код сделан так, что если я нажму на клиенте кнопку отмены, то цикл recv на клиенте прервётся, из за изменения глобальной переменной. (после нажатия кнопки и получения команды "отмены" на клиенте - логер пишет что "ухожу в сон", ну и как я уже сказал sleep(xxx))

2 гб или 20 мегабайт, разницы нету. Я тестировал это поведение на 40 кб файле, если я нажимаю отмену где то в середине.
Ещё раз. Без отмены, пока клиент реально ждёт посылки файла - всё нормально, и если я ему не мешаю, то файл скачивается полностью.

Вопрос в том, почему send на сервере не возвращяет 0 или SOCKET_ERROR, ведь на клиенте recv прерывается. Коннект я не глушу, т.е. shutdown'a нет.

Цитата Сообщение от vxg Посмотреть сообщение
легче клиенту послать на сервер сообщение
Сервер не примет его, ведь у него текущяя задача - send file. Он не может выйти в recv состояние пока не вышлет весь файл, или пока send не вернёт значение отличное от размера посылаемого пакета (включая error).

У меня предположение, что локальная сеть во всём виной, т.е. поведение send и recv отличны в интернете и в локалке, хотя какое то бредовое предположение. Я честно говоря уже голову сломал с этим недоразумением.
0
vxg
Модератор
3252 / 2052 / 323
Регистрация: 13.01.2012
Сообщений: 7,949
07.02.2018, 21:16 4
Цитата Сообщение от Izual Посмотреть сообщение
У меня размер буффера 1024 байт
покажите код где это будет видно
0
Izual
142 / 120 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
07.02.2018, 21:32  [ТС] 5
Кусок серверной части (отдельный поток для каждого клиента)
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
char fBuf[1024]=""; //выделяется при старте потока
while(1)
    {
        Sleep(5000);
        //проверка ошибок
        if(si[fCn].st % 2)
        {
            memset(fBuf, 0, _countof(fBuf));
            fSz = recv(sock, fBuf, 1024, 0);
            if(fSz < 1 || fSz > 1022)
            {
                if(fSz == 0)
                {
                    sprintf(fLbuf,"cPC[%ld] #ERROR# o.Recv ret=0.", fCn);
                    fErr[0]=-1;
                }
                else if(fSz == -1)
                {
                    sprintf(fLbuf,"cPC[%ld] #ERROR# o.Recv ret=SOCKET_ERROR.", fCn);
                    fErr[0]=-2;
                }
                else
                {
                    sprintf(fLbuf,"cPC[%ld] #ERROR# o.Recv OOR:ret=%ld.", fCn, fSz);
                    fErr[0]=-3;
                }
                LogMessage(fLbuf);
                continue;
            }
            sprintf(fLbuf,"cPC[%ld] RECV ret=%ld(b)", fCn, fSz);
            LogMessage(fLbuf);
            fBuf[fSz] = '\0';
            fErr[3]=fMessager(fCn, fBuf, fSz); // тут обработка
            if(fErr[3] != 1)
            {
                sprintf(fLbuf,"cPC[%ld] #ERROR# o.Recv.fMsg() ret=%ld cST=%ld nST=%ld.", fCn, fErr[3], fStc, si[fCn].st);
                LogMessage(fLbuf);
                fErr[0]=-4;
                break;
            }
            sprintf(fLbuf,"cPC[%ld] #OK# o.Recv ret=%ld(b) cST=%ld nST=%ld", fCn, fSz, fStc, si[fCn].st);
            LogMessage(fLbuf);
        }
        else // 2 4
        {
            fErr[3]=fMessager(fCn, fBuf, fSz);
            if(fErr[3] != 1)
            {
                sprintf(fLbuf,"cPC[%ld] #ERROR# o.Send.fMsg() ret=%ld cST=%ld nST=%ld.", fCn, fErr[3], fStc, si[fCn].st);
                LogMessage(fLbuf);
                fErr[0]=-10;
                break;
            }
            if(fSz < 1 || fSz > 1024)
            {
                sprintf(fLbuf,"cPC[%ld] #ERROR# o.Send OOR:(fsz)%ld.", fCn, fSz);
                LogMessage(fLbuf);
                fErr[0]=-11;
                break;
            }
            ret = send(sock, fBuf, fSz, 0);//sizeof(fBuf), 0);
            if(ret == SOCKET_ERROR)
            {
                sprintf(fLbuf,"cPC[%ld] #ERROR# o.Send ret=SOCKET_ERROR.", fCn);
                LogMessage(fLbuf);
                fErr[0]=-12;
                continue;
            }
            if(ret != fSz)
            {
                sprintf(fLbuf,"cPC[%ld] #ERROR# o.Send (ret)%ld != (fsz)%ld.", fCn, ret, fSz);
                LogMessage(fLbuf);
                fErr[0]=-13;
                break;
            }
            sprintf(fLbuf,"cPC[%ld] #OK# o.Send ret=%ld(b) cST=%ld nST=%ld", fCn, ret, fStc, si[fCn].st);
            LogMessage(fLbuf);
        }
    }
Ничего особенного...
Клиент:
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
Sleep(5000);
            fStc=m.st;
            if(m.st % 2)
            {
                fArr[0]=fMessager();
                if(fArr[0]!=1)
                {
                    sprintf(fLbuf,"#ERROR# o.Send.fMsg() ret=%ld cST=%ld nST=%ld", fArr[0], fStc, m.st);
                    LogMessage(fLbuf);
                    fErr[5]=-1;
                    continue;
                }
                if(fsz < 1 || fsz > 1023)
                {
                    sprintf(fLbuf,"#ERROR# o.Send.fMsg() sz=%ld cST=%ld", fsz, fStc);
                    LogMessage(fLbuf);
                    fErr[5]=-2;
                    continue;
                }
                ret = send(sClient, szBuf, fsz, 0);
                if(ret != fsz)
                {
                    if(ret == SOCKET_ERROR)
                    {
                        sprintf(fLbuf,"#ERROR# o.Send ret=SOCKET_ERROR cST=%ld", fsz, fStc);
                        fErr[5]=-3;
                    }
                    else
                    {
                        sprintf(fLbuf,"#ERROR# o.Send ret=%ld sz=%ld cST=%ld", ret, fsz, fStc);
                        fErr[5]=-4;
                    }
                    LogMessage(fLbuf);
                    continue;
                }
                sprintf(fLbuf,"o.Send cST=%ld nST=%ld", fStc, m.st);
                LogMessage(fLbuf);
                //-
            }
            else
            {
                memset(szBuf, 0, _countof(szBuf));
                fsz = recv(sClient, szBuf, 1024, 0);
                if(fsz < 1 || fsz > 1023)
                {
                    if(fsz == -1)
                    {
                        sprintf(fLbuf,"#ERROR# o.Recv ret=SOCKET_ERROR cST=%ld", fStc);
                        fErr[5]=-11;
                    }
                    else
                    {
                        sprintf(fLbuf,"#ERROR# o.Recv ret=%ld cST=%ld", fsz, fStc);
                        fErr[5]=-12;
                    }
                    LogMessage(fLbuf);
                    continue;
                }
                sprintf(fLbuf,"o.Recv ret=%ld(b)", fsz);
                LogMessage(fLbuf);
                szBuf[fsz] = '\0';
                fArr[0]=fMessager();
                if(fArr[0]!=1)
                {
                    sprintf(fLbuf,"#ERROR# o.Recv.fMsg() ret=%ld cST=%ld nST=%ld", fArr[0], fStc, m.st);
                    LogMessage(fLbuf);
                    fErr[5]=-13;
                    continue;
                }
                sprintf(fLbuf,"o.Recv cST=%ld nST=%ld", fStc, m.st);
                LogMessage(fLbuf);
                //-
            }
Так же в цикле.. буфер - глобальный, т.к. поток у клиента один (ну не считая оконные потоки для логера и т.п.)
C++
1
char szBuf[1024]="";
Как видиш, ничего сверхъестественного..
Думаю что код ничему не поможет.. В общем я попробую попозже сделать более простой клиент-серверный, и буду тестить, т.к. текущий проэкт очень большой.
0
vxg
Модератор
3252 / 2052 / 323
Регистрация: 13.01.2012
Сообщений: 7,949
08.02.2018, 07:37 6
Izual, как "видиш" код твоего "проэкта" однозначно говорит умеющим читать о том что ты путаешь понятия буфер системы и буфер в который ты попросил систему отсыпать из системного буфера немножко данных: по коду 1024 - это размер второго буфера, система буферизирует гораздо большие объёмы и то что ты не хочешь их забирать из системного буфера к себе не останавливает их поступление если вторая сторона бездумно продолжает их посылать - буферизация будет продолжаться пока не переполнятся буфера на обеих машинах - в начале буфер приёма на принимающей, следом начнёт заполнятся и переполнится буфер отправки на передающей. Как видишь ничего особенного...

Добавлено через 2 минуты

Не по теме:

Может рано ещё большой проект то заваливать?

0
Izual
142 / 120 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
08.02.2018, 14:21  [ТС] 7
Мне кажется что ты троллиш.

Какой системный буффер?.. Файл подкачки?.. О чём ты?..

Цитата Сообщение от vxg Посмотреть сообщение
1024 - это размер второго буфера
Они оба 1024. И посылающий и принимающий.

Цитата Сообщение от vxg Посмотреть сообщение
система буферизирует гораздо большие объёмы
Силикон качает?..

Цитата Сообщение от vxg Посмотреть сообщение
не останавливает их поступление если вторая сторона бездумно продолжает их посылать
Ну да, а SOCKET_ERROR для чего?

Цитата Сообщение от vxg Посмотреть сообщение
Может рано ещё большой проект то заваливать?
Я сделал некоторые выводы про то кто ты и что ты пытаешся мне тут втюхать. Больше не пиши тут, мне твои комменты не нужны.
0
vxg
Модератор
3252 / 2052 / 323
Регистрация: 13.01.2012
Сообщений: 7,949
08.02.2018, 19:00 8
Izual, расширьте кругозор начав например отсюда https://stackoverflow.com/questions/...and-so-recvbuf
0
Izual
142 / 120 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
08.02.2018, 21:14  [ТС] 9
Цитата Сообщение от vxg Посмотреть сообщение
начав например отсюда
Я конешно признателен за помощь. Но, есть большое "НО".
1. На форуме нельзя размещять ссылки на сторонние ресурсы. (в связи с этим у меня уже двоякое мнение лично о вас, а о правилах форума я промолчу вовсе, ибо нет смысла)
2. Даже в этом топике написано, что сокет будет выбрасывать ошибку. А у меня ошибку он не выбрасывает вовсе. Так что это всё совсем другая история, и не надо меня путать понятиями, которые может и полезны для ознакомления, но совершенно безполезны в конкретном вопросе.

Остаюсь с предположением, что это локальная сеть так работает криво, ибо я сталкивался и с другими непонятными явлениями, которых не было в локальном тесте, но были в интернет.
0
GbaLog-
09.02.2018, 06:34
  #10

Не по теме:

Цитата Сообщение от Izual Посмотреть сообщение
1. На форуме нельзя размещять ссылки на сторонние ресурсы.
на другие форумы - нельзя.
на русский stackoverflow - нельзя.
на английский - можно.
почему так - не знаю, уточняйте у администрации самостоятельно.
плюс к этому: вы думаете, что модератор правил не знает что ли?

0
vxg
Модератор
3252 / 2052 / 323
Регистрация: 13.01.2012
Сообщений: 7,949
09.02.2018, 08:45 11
Izual, про правила форума вам постом выше человек все доходчиво объяснил, а про буферы - читайте внимательнее что там написано: рассмотрим системный буфер приёма - в системе для каждого сокета резервируется системный буфер размер которого можно узнать / изменить при помощи вызовов get / setsockopt - в этот системный буфер данные поступают прямо от адаптера даже когда вы не вызываете recv, вызов recv забирает данные из этого системного буфера и помещает их в указанную вами область памяти в количестве меньшом либо равным указанному вами. По вашему коду нигде не устанавливаются размеры системных буферов (нет вызовов setsockopt) поэтому логично предположить что они имеют значения по умолчанию которые зависят от ОС и в данном случае оказались достаточными для размещения всех данных которые не захотел принимать ваш клиент без того чтобы спровоцировать ошибку передачи на сервере
0
09.02.2018, 08:45
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
09.02.2018, 08:45

SOCKET: send(), recv()
Начал разбираться с сокетами и в самом начале застрял на элементарном, с...

NetBIOS ф-ии Send и Receive
При операциях с NetBios есть две функции SEND (которая отправляет) и RECEIVE...

Когда возвращает управление send?
Функция send возвращает управление, если все данные отправятся (не факт что...


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

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru