Посылаю сообщение серверу и не получаю ответа. Смотрел поиском — такая тема уже поднималась когда кто-то пытался получить ответ от сервера на логин и ему дали кучу примеров. У меня похожая проблема:
соединяюсь с почтовым сервером и скачиваю файл ~300 кб. С помощью такого куска кода:
while (BufLen>0)
{
Sleep(100);
BufLen=ServerSocket.Receive(lpBuf,65536,0);
// write to the file
if (BufLen<=0) break;
fletter.Write(lpBuf,BufLen);
}
Когда делаю это дебаггером пошагово, то все принимается.
Иначе, в файл записывается тока 3 первых байта.
Если сделать Sleep(500), тогда такой файл благополучно принимается.
Если туда скинуть файл размером 2 метра, тогда такая же фигня получается.
Если сделать Sleep слишком большой, тогда прием файла будет очень долгим.
Подскажите плз как это технично реализовать.
Z>while (BufLen>0)
Z>{
Z> Sleep(100);
Z> BufLen=ServerSocket.Receive(lpBuf,65536,0);
Z>// write to the file
Z> if (BufLen<=0) break;
Z> fletter.Write(lpBuf,BufLen);
Z>}
Z>Когда делаю это дебаггером пошагово, то все принимается. Z>Иначе, в файл записывается тока 3 первых байта. Z>Если сделать Sleep(500), тогда такой файл благополучно принимается. Z>Если туда скинуть файл размером 2 метра, тогда такая же фигня получается. Z>Если сделать Sleep слишком большой, тогда прием файла будет очень долгим. Z>Подскажите плз как это технично реализовать.
Вы используете MFC сокеты?
Вот тут нверно нужно быть менее жестоким if (BufLen<=0) break; и проверять, что возвращает WSAGetLastError(), соответсвтенно читать только тогда, когда есть что читать..
Z>while (BufLen>0) Z>{ Z> Sleep(100); Z> BufLen=ServerSocket.Receive(lpBuf,65536,0); Z>// write to the file Z> if (BufLen<=0) break; Z> fletter.Write(lpBuf,BufLen); Z>} Z>Когда делаю это дебаггером пошагово, то все принимается. Z>Иначе, в файл записывается тока 3 первых байта. Z>Если сделать Sleep(500), тогда такой файл благополучно принимается. Z>Если туда скинуть файл размером 2 метра, тогда такая же фигня получается. Z>Если сделать Sleep слишком большой, тогда прием файла будет очень долгим. Z>Подскажите плз как это технично реализовать.
Простейший способ — заменить async socket на Berkeley вызовы, и вот тогда все заработает без Sleep, конечно.
Async socket дает много функциональности, которая в данном случае просто лишняя и ненужная (за исключением случая, когда нужен минимум нагрузки процессора на гигабитной сети).
Здравствуйте, butcher, Вы писали:
B>Вы используете MFC сокеты? B>Вот тут нверно нужно быть менее жестоким B>if (BufLen<=0) break; и проверять, что возвращает WSAGetLastError(), соответсвтенно читать только тогда, когда есть что читать..
Да, я использую CAcyncSocket:
////////////////////////////////////////////////////////////////////////////
if (!ServerSocket.Create(0,SOCK_STREAM,FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE,NULL))
{
AfxMessageBox("Îøèáêà ñîçäàíèÿ ñîêåòà");
}
ServerSocket.Connect(serverIP,110);
////////////////////////////////////////////////////////////////////////////
Проверил что возвращает функция GetLastError() — она говорит WSAEWOULDBLOCK, т.е. как написано в МСДН нет входящих данных. На самом деле, если пройти этот кусок кода дебаггером, то данные получим. Принимается даже двухметровый файл. Когда в режиме выполнения, то — WSAEWOULDBLOCK . Если я скажу читать с сокета и при WSAEWOULDBLOCK, то по какому признаку выходить из цикла??? Я думаю что в режиме выполнения почтовый сервер не успевает запихивать данные в сокет, а программа думает что данные кончились. Как быть???
Здравствуйте, zaxs, Вы писали:
Z>Да, я использую CAcyncSocket: Z>Проверил что возвращает функция GetLastError() — она говорит WSAEWOULDBLOCK, т.е. как написано в МСДН нет входящих данных. На самом деле, если пройти этот кусок кода дебаггером, то данные получим. Принимается даже двухметровый файл. Когда в режиме выполнения, то — WSAEWOULDBLOCK . Если я скажу читать с сокета и при WSAEWOULDBLOCK, то по какому признаку выходить из цикла??? Я думаю что в режиме выполнения почтовый сервер не успевает запихивать данные в сокет, а программа думает что данные кончились. Как быть???
WSAEWOULDBLOCK означает, что операция ввода/вывода требует блокировки для удачного завершения, другими словами в данный момент система не готова вам отдать данные. Когда вы в дебагере принмаете, то между каждым вызовом recv система успевает принять данные, обработать их соответсвующим образом и отдать вам.
Что делать вам: вам нужно изменить алгоритм приёма, т.е. читать данные до ошибки WSAEWOULDBLOCK, потом ждать следующего FD_READ и читать дальше, в случае возниконовения другой ошибки обрабатывать её соответствующим образом.
Здравствуйте, Maxim S. Shatskih, Вы писали:
MSS>Простейший способ — заменить async socket на Berkeley вызовы, и вот тогда все заработает без Sleep, конечно.
MSS>Async socket дает много функциональности, которая в данном случае просто лишняя и ненужная (за исключением случая, когда нужен минимум нагрузки процессора на гигабитной сети).
Да, видимо придется пользоваться блокирующим сокетом, а не асинхронным. Надо было сразу таким пользоваться. Решил МФСишными функциями пользоваться и зря. С ними одни проблемы — даже в многопоточном режиме они глючат в версии 6 и ниже. Спасибо за совет.
Здравствуйте, butcher, Вы писали:
B>WSAEWOULDBLOCK означает, что операция ввода/вывода требует блокировки для удачного завершения, другими словами в данный момент система не готова вам отдать данные. Когда вы в дебагере принмаете, то между каждым вызовом recv система успевает принять данные, обработать их соответсвующим образом и отдать вам. B>Что делать вам: вам нужно изменить алгоритм приёма, т.е. читать данные до ошибки WSAEWOULDBLOCK, потом ждать следующего FD_READ и читать дальше, в случае возниконовения другой ошибки обрабатывать её соответствующим образом.
Точно так. Стормозил и неправильно понял МСДН — библию программиста . Т.е. проблема решаема. Спасибо. Только я вот почитал ответ от "Maxim S. Shatskih" и сделал аналогичный пример, но на блокирующих сокетах без использования МФС. Там действительно не нужно делать Sleep. Вот как выглядит последний самый интересный кусок кода:
////////////////////////////////////////////////////////
CStdioFile zaxs;
zaxs.Open("letter",CFile::modeCreate|CFile::modeWrite);
while(bait>0)
{
bait=recv (srv_socket , szBuf, 65536, 0);
zaxs.Write(szBuf,bait);
}
zaxs.Close();
AfxMessageBox("файл скачан");
closesocket (srv_socket);
/////////////////////////////////////////////////////////////////
Т.е. принимает она нормально, но до поры до времени — пока данные не кончатся, а потом тормоза... В принципе как в теме CAcyncSocket&recv указано, можно через list узнать сколько байт точно нужно читать, но решение честно говоря некрасивое. Неужели нет другого выхода???
Здравствуйте, Maxim S. Shatskih, Вы писали:
MSS>Простейший способ — заменить async socket на Berkeley вызовы, и вот тогда все заработает без Sleep, конечно.
MSS>Async socket дает много функциональности, которая в данном случае просто лишняя и ненужная (за исключением случая, когда нужен минимум нагрузки процессора на гигабитной сети).
сделал аналогичный пример, но на блокирующих сокетах без использования МФС. Там действительно не нужно делать Sleep. Вот как выглядит последний самый интересный кусок кода:
////////////////////////////////////////////////////////
CStdioFile zaxs;
zaxs.Open("letter",CFile::modeCreate|CFile::modeWrite);
while(bait>0)
{
bait=recv (srv_socket , szBuf, 65536, 0);
zaxs.Write(szBuf,bait);
}
zaxs.Close();
AfxMessageBox("файл скачан");
closesocket (srv_socket);
/////////////////////////////////////////////////////////////////
Т.е. принимает она нормально, но до поры до времени — пока данные не кончатся, а потом тормоза... В принципе как в теме CAcyncSocket&recv указано, можно через list узнать сколько байт точно нужно читать, но решение честно говоря некрасивое. Неужели нет другого выхода???
Здравствуйте, zaxs, Вы писали:
Z>Точно так. Стормозил и неправильно понял МСДН — библию программиста . Т.е. проблема решаема. Спасибо. Только я вот почитал ответ от "Maxim S. Shatskih" и сделал аналогичный пример, но на блокирующих сокетах без использования МФС. Там действительно не нужно делать Sleep. Вот как выглядит последний самый интересный кусок кода:
Дак на то они и блокирующие сокеты.
Z>Т.е. принимает она нормально, но до поры до времени — пока данные не кончатся, а потом тормоза... В принципе как в теме CAcyncSocket&recv указано, можно через list узнать сколько байт точно нужно читать, но решение честно говоря некрасивое. Неужели нет другого выхода???
Нужно делать select перед вызовом recv, если select скажет вам что можно читать — вперёд, иначе попадаете в блокировку.
Воспользуйтесь поиском по форуму, неделю или две назад я кидал сюда пример с использованием select.
Здравствуйте, butcher. Сделал обработку ошибок:
while (BufLen>0)
{
Sleep(100);
BufLen=ServerSocket.Receive(lpBuf,65536,0);
// tema.Format("%d",BufLen);
// AfxMessageBox(tema);
// write to the file
if (BufLen<=0)
{
equal_flag=ServerSocket.GetLastError();
SetLastError(10000);
// equal_flag=ServerSocket.GetLastError();
if(equal_flag==WSAEWOULDBLOCK)
{
BufLen=1;
continue;
}
break;
}
fletter.Write(lpBuf,BufLen);
}
только очередная засада: даже когда данные кончаются все равно выдается ошибка WSAEWOULDBLOCK. Думал что он запомнил последнюю ошибку и не обновляет ее поэтому вставил строку: SetLastError(10000); но все равно продолжает генерироваться такая ошибка.
Здравствуйте, zaxs, Вы писали:
Z>Здравствуйте, butcher. Сделал обработку ошибок: Z>while (BufLen>0) Z>{ Z> Sleep(100); Z> BufLen=ServerSocket.Receive(lpBuf,65536,0); Z>// tema.Format("%d",BufLen); Z>// AfxMessageBox(tema);
Z> // write to the file Z> if (BufLen<=0)
Когда функция Receive возвращает 0 — это означает, что соединение закрыто с "той" стороны, это не ошибка и это нужно обрабатывать соответсвующим образом.
Z> { Z> equal_flag=ServerSocket.GetLastError(); Z> SetLastError(10000); Z>// equal_flag=ServerSocket.GetLastError(); Z> if(equal_flag==WSAEWOULDBLOCK) Z> { Z> BufLen=1; Z> continue; Z> } Z> break; Z> } Z> fletter.Write(lpBuf,BufLen); Z>}
Z>только очередная засада: даже когда данные кончаются все равно выдается ошибка WSAEWOULDBLOCK. Думал что он запомнил последнюю ошибку и не обновляет ее поэтому вставил строку: SetLastError(10000); но все равно продолжает генерироваться такая ошибка.
Я же говорю, в Re[3]: CAsyncSocket&Receive
, эта ошибка будет произходить всегда при работе с неблокирующими сокетами, когда результат не может быть возвращён немедленно.
Нет ничего невозможного..
Re[8]: CAsyncSocket&Receive
От:
Аноним
Дата:
16.06.04 06:58
Оценка:
Снова жопа: написал код блокирующими сокетами и сделал вызов select
сначала все было круто, а потом я снова попал. селект все время возвращает 0 — выходит по таймауту. И когда там данных нет, и когда их туда не успевают засунуть. Снова таже бодяга: увеличивать таймаут в ущерб производительности, а вдруг там окажется файл чуть больше чем я предполагаю?
видимо не получится корректно скачивать файл чисто системными средсвами — придется делать проверку на точку в конце данных и тогда прекращать прием данных с сокета.
Здравствуйте, <Аноним>, Вы писали:
А>Снова жопа: написал код блокирующими сокетами и сделал вызов select А>сначала все было круто, а потом я снова попал. селект все время возвращает 0 — выходит по таймауту. И когда там данных нет, и когда их туда не успевают засунуть. Снова таже бодяга: увеличивать таймаут в ущерб производительности, а вдруг там окажется файл чуть больше чем я предполагаю?
Что значит "увеличивать таймаут в ущерб производительности", вы можете определить величину таймаута после которого вы будете "думать, что всё плохо". После этого таймаута рвёте связь и считаете, что передача не удалась.
Величина таймаута, когда "всё нормально" — не влияет на производительность, так как select не "держит" программу пока не истечёт таймаут, а "отпускает" как только данные появятся.
while(1)
{
flag=select(0,&zaxs12,NULL,NULL,&timez);
if(flag==0)
{
zaxs12.fd_count=1;
continue;
}
if(flag==1)
{
bait=recv (srv_socket , szBuf, 32768, 0);
zaxs.Write(szBuf,bait);
}
else
{
err=WSAGetLastError();
temp.Format("%d",err);
AfxMessageBox(temp);
break;
}
}
дело в том, что я данные не все получаю как выяснилось, а только процентов 99. и функция селект все время выдает 0.
Здравствуйте, zaxs, Вы писали:
Z>так примерно я и делаю и даже использую эти макросы, результат тот же.
значит что-то не так делаете
Почему же вы тогда код приводите не такой?
Z>Но ведь это как то реализовано! например в оутлуке или еще где то.
А кто сомневается, если делать правильно — всё будет работать, даже с асинхронными сокетами