- Как исправить ошибку «Работа с сокетами: Ошибка! Не работает.»
- Почему появляется ошибка?
- На что эта ошибка влияет?
- Как исправить ошибку?
- Требуется наша помощь?
- Из-за чего падает сокет-сервер?
- Почему сокет не работает при многопоточности?
- Решение
- Другие решения
- Как можно определить почему не работает связь с сервером (WebSocket)?
- Форум программистов «Весельчак У»
- Программирование => WinAPI & Visual C++ => Тема начата: Mikl от 03-07-2009 17:56
Как исправить ошибку «Работа с сокетами: Ошибка! Не работает.»
Почему появляется ошибка?
Ошибка появляется в случае, если сайт не может подключиться к себе же, используя сокеты.
Причины возникновения проблемы могут быть самые разные, приведем наиболее часто встречающиеся:
- сайт был недавно перенесен на новый сервер, у него были изменены NS-сервера, но они еще в стадии обновления.
- текущий сайт является копией сайта и работает на стороннем сервере под основным доменом, для обеспечения работоспособности в файле hosts прописан IP нового сервера,
- в /etc/hosts (для Linux) или C:\Windows\System32\drivers\etc\hosts (для Windows) прописан некорректный IP-адрес для текущего хоста.
- другие проблемы, касающиеся DNS,
- проблема с http-авторизацией,
- некорректные редиректы на сервере,
- у вас локальный сайт, который недоступен извне,
- проблема с SSL-сертификатом.
Более точно причину можно понять, посмотрев лог проверки сайта — он находится в папке /bitrix/ и имеет формат имени site_checker_*.log.
На что эта ошибка влияет?
Если проверка на работу сокетов не проходит, то другие тесты также не могут быть выполнены: «Замечание. Не удалось проверить из-за ошибки в работе с сокетами».
При этом, в большинстве случаев сайт продолжает нормально работать.
Как исправить ошибку?
Способ решения в полной мере зависит от причины.
Опишем так же по пунктам:
- в случае недавнего переезда сайта на новый сервер достаточно просто подождать, процесс обновления DNS обычно занимает несколько часов, но может занять до нескольких дней, этот процесс зависит от разных факторов,
- в данном случае необходимо в файле hosts прописать правило для домена, обычно это делается в той же строке, где и localhost — добавить домен сайта в конце строки,
- в этом случае нужно просто убрать некорректную запись из hosts,
- в случае других проблем с DNS необходимо более детально изучать вопрос и обращаться к специалистам,
- необходимо корректно сконфигурировать сервер (в т.ч. файл .htaccess),
- необходимо корректно настроить редиректы, также учитывая порт подключения,
- решение такое же как в пункте 2 — необходимо отредактировать hosts, добавив имя текущего домена,
- проверьте корректность установки SSL-сертификата.
Требуется наша помощь?
Мы имеем огромный опыт, на протяжении 10 лет помогая клиентам в решении самых различных проблем на их сайтах.
Поэтому, если Вы не имеете возможности решить эту проблему самостоятельно, обращайтесь к нам — мы все сделаем оперативно и квалифицированно.
По всем вопросам обращайтесь по нашим контактным данным:
Источник
Из-за чего падает сокет-сервер?
Connection reset by peer (Соединение сброшено сервером)
Connection reset by peer может вызываться совершенно разными причинами. В общем случае сервер определяет, что сокет больше не работает нормально и закрывает его со своей стороны.
5.1 Read Error (Ошибка чтения)
Сценарий: Мэри не может понять, что говорит Джо, и вешает трубку вместо того, чтобы терять его сообщения (данные).
Ошибка чтения возникает когда сервер не может успешно прочитать данные от клиента. Сервера собирают информацию от клиента и когда получают ошибку при чтении данных, отключают пользователя, что приводит к сообщению «Read Error» при выходе.
5.2 Write Error (Ошибка записи)
Сценарий: Мэри пытается говорить с Джо, но полагает, что он ее не слышит. Поэтому она вешает трубку вместо того, чтобы мириться с потерей сообщений (данных).
Ошибка записи возникает когда сервер не может успешно записать информацию в клиента. При получении сервером информации, он обычно отвечает на это своими данными клиенту. Если сервер получает ошибку при записи в клиент, он отключает пользователя, и это приводит к сообщению «Write Error» по формату сходному с «Read Error»
5.3 Ping Timeout (эээ.. Пинг таймаут!)
Сценарий: Мэри, завозившись по хозяйству с детьми и сильно отвлекаясь, постоянно спрашивает Джо, слушает ли он ее. И если не получает ответа достаточно быстро — вешает трубку.
Сервер автоматически пингует пользователя через определенный промежуток времени. Это делается для того, чтобы убедиться, что клиент все еще на связи. Когда Вы видите сообщения «PING? PONG!» в окне статуса, это означает, что сервер послал пинг-запрос на Вашу машину и она отослала ему понг-ответ. Если Вы отключаетесь, а сервер не знает об этом, то он автоматически сбросит Ваш ник из сети после того, как долго не будет получать понг-ответы, что выльется в квит по «пинг таймауту». Такое может произойти с любым.
5.4 Broken pipe (Нарушенный пайп)
Сценарий: Мэри обнаружила записку с сообщением, которое ей надо было передать Джо, но каким-то образом, между запиской и ее ртом сообщение потерялось. Мэри пытается передать Джо содержание, но не уверена, что у нее это выходит и вешает трубку полагая это лучшим вариантом, чем потеря информации (данных).
Ошибка «сломанного пайпа» возникает когда сервер понимает, что у него есть сообщение для отсылки вовне, но он не может подать его на сокет из-за внутренний ошибки передачи данных.
5.5 Остальные ошибки
Сценарий: Множество вариантов; возможно в разговор вмешался оператор и это заставило Мэри усомниться в правильности звонка и она повесила трубку.
Источник
Почему сокет не работает при многопоточности?
У меня очень просто recvfrom() команда, которая работает нормально — до тех пор, пока она не вызывается в «другом» потоке.
Я бы опубликовал больше кода, но его довольно много, поэтому, надеюсь, я смогу отфильтровать соответствующие биты:
Сначала у нас есть глобальная переменная: SOCKET Socket=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); ,
Пока потоки не вовлечены, это работает отлично:
Теперь у меня есть идентичный код, вызываемый в потоке, например:
pthread_create(&listener, NULL, listenloop, &Socket);
(Код в основном игнорирует &socket .)
Первый recvfrom() выполнить из вызываемого потока, возвращает -1, но recvfrom() из «оригинального» потока (где была настроена сеть) успешно заполняет message с, ну, сообщением с сервера.
Так любезно сказать мне, что я делаю не так?
РЕДАКТИРОВАТЬ: Я не хочу бросать более десятка строк в незнакомцев, достаточно любезных, чтобы помочь мне, но я не думаю, что получу ответ, если не сделаю этого. Итак, вот набор и kaboodle, слегка отредактированные:
Решение
Почему вы используете глобальный Socket ? И почему ты объявляешь другого Socket в основном? Вы должны лучше использовать сокет, переданный в pthread_create (только что бросил args в прослушивании SOCKET * ). Глобальные переменные в многопоточном режиме — очень плохая идея (вам нужен механизм синхронизации). И инициализировать ваш struct sockaddr_in from с нулями (например, с memset или просто сделай, как сказал алк: struct sockaddr_in from = <0>).
А также вы читаете из одного сокета в двух разных потоках без какой-либо синхронизации. Это должно вызвать много ошибок.
А также я вижу проблему с WSACleanup а также recvfrom в другой теме. Вы не знаете, в каком порядке эти два бегут (так что вы также можете получить WSACleanup прежде чем ты сможешь recvfrom в другой теме). Можно использовать pthread_join ждать завершения другого потока и затем делать WSACleanup ,
Другие решения
Это слишком долго для комментария.
Размещенный код не будет работать вообще из-за объявления:
а затем с помощью from как это:
Вы переводите адрес в адрес struct sockaddr_in а не только его адрес.
Это должно быть:
Однако, если вы делаете это, вы не можете выделить память для from ,
Источник
Как можно определить почему не работает связь с сервером (WebSocket)?
Part 1
Как можно определить почему не работает связь с сервером?
Web-server: OpenServer
Алиас — localhost —- yii333.com
Вообще по разному пробовал, и без алиаса.
Включал/выключал — защитить сервер от внешнего доступа
Фаервол: выключен
Используемая библиотека websocket: socketo.me
Проверка включение websockets на веб-сервере: Всё отрабатывает на отлично!
Running It ¶ Complete, let’s run it and test it. Open up three terminal windows, typing:
$ php bin/chat-server.php $ telnet localhost 8080 $ telnet localhost 8080 In each of the telnet windows, type a message («Hello World!») and see it appear in the other!
всё отлично работает, связь есть, сообщения пересылаются.
Когда перехожу к следующему шагу Next Steps
Next Steps ¶ Now that we have a basic working Chat application, let’s make that work in a web browser (Chrome, FireFox, or Safari [for now]). First, let’s go back to our chat-server.php script. We’re going to utilize another component of Ratchet; the WsServer class:
var conn = new WebSocket(‘ws://localhost:8080’); conn.onopen = function(e) < console.log("Connection established!"); >;
WebSocket connection to ‘ws://localhost:8080/’ failed: Error during WebSocket handshake: Unexpected response code: 400
этот код я отправлял как через консоль браузера, так и через html страничку. Перед тем как отправлять js код, я запускаю сервер через консоль, запущенную от имени администратора php bin/chat-server.php
Так-же, показывает что ошибка произошла в этой строке JS скрипта, если запускать скрипт через html страницу :
Если в адресной строке браузера набрать localhost:8080 то выдает ошибку:
Если в адресной строке браузера набрать localhost6:8080 или другой какой-нибудь адрес сервера, или выключить сервер, то выдаёт ошибку:
Part 2
Связь удалось настроить между сервером и клиентом.
Но, связь с сервером нестабильна. Если мы первый раз попытаемся соединиться через JS скрипт, то получим ошибку 400. Если мы будет обновлять страницу, тем самым перезагружая js скрипт, то примерно с второго/пятнадцатого раза, произойдёт связь с сервером. На сервере в консоли, отобразится лог о том что создан новый коннект. При отправки сообщения на сервер, поведение не менее странное. Мы можем отправить сообщение и сервер его прочитает и отобразит в консоли, а может и вообще не прочитать и ничего не отобразить в консоли. Причину всего этого, пока не удалось выяснить.
Источник
Форум программистов «Весельчак У»
Программирование => WinAPI & Visual C++ => Тема начата: Mikl от 03-07-2009 17:56
| Название: Сервер сокетов перестает работать Отправлено: Mikl от 03-07-2009 17:56 |
Уважаемые, подскажите ЕСЛИ кто сталкивался.
Есть набор клиент-серверных приложений собственной разработки. Для связи используются сокеты в виде классов в которых реализовна и клиентская и серверная части. Вся часть ПО ответственная за связь вынесена в отдельную DLL.
Сервер запускается, клиенты к нему подключаются, отключаются и т.д. и т.п.
Все нормально работало неделями — дольше не получалось тестировать непрерывно — приходилось перезапускать.
Клиентов было штук 20.
Сейчас клиентов увеличил до 150. Теперь все работает но 2,5 дня. Может и дольше — до недели, но не меньше точно.
Потом происходит следующая ситуация. Сервер видит подключения клиентов, новые подключаются, старые отключаются, но данные не пересылаются ни в одну сторону.
Была идея — сделать перезапуск класса сервера, отвечающего за связь. Обнаружил интересную штуку — если сделать этот перезапуск искусственно — скажем через 1 сутки — все нормально работает. Но если дождаться когда связь «отвалится» сама — увы, клиенты подключаются, а данные не ходят ни в одну сторону.
Перезапускаешь приложение — все опять работает.
Понятно, что где-то что-то переполняется, но вот что и где.
Идеи есть какие-нибудь?
Спасибо.
Хорошо. С другой стороны зайдем. Когда твое приложение зависло. В диспетчере задач. Сколько памяти выделено для твоего приложения. Также, сколько нитей? Также эти цифри в рабочем состоянии.
Также программа netstat. Сколько открытых сокетов показано, которые принадлежат твоему приложению?
Кстати, у Виндовс есть лимит открытых сокетов. И по умолчанию он довольно маленький. Не превышаеш ли ты его?
Приложение НЕ зависло. Оно как работало — так и работает. Срабатывают функции перезапуска модуля связи.
Дальше я жду — ничего нет (в смысле данные не идут) и нажимаю в приложении кнопку выход — все КОРРЕКТНО завершается без каких-либо утечек чего-либо :-(.
Памяти сколько выделено и нитей — столько же, сколько и при старте программы.
А вот насчет netstat — сказать ничего не могу — я только что про нее узнал — пока есть данные только ДО падения связи. Жду когда упадет — с учетом запланированного на завтра перезапуска — где-то в понедельник, не раньше.
Добавлено через 1 минуту и 15 секунд:
Да, еще забыл добавить интересное наблюдение — перезапуск класса связи искусственно срабатывает 101 раз. А потом надо один фиг перезагружать всю программу целиком.
UINT Potok(LPVOID pParam)
<
SOCKADDR_IN saddr;
WSADATA data;
int optval = 1;
int rc;
rc = setsockopt(mainSocket, SOL_SOCKET, SO_REUSEADDR,
(char *)&optval, sizeof(optval));
if (bind(mainSocket,(PSOCKADDR) &saddr,sizeof(SOCKADDR_IN)))
<
DWORD mmm999=GetLastError();
Fl_Err=3;return 0;
>
Fl_Err=1;
if (listen(mainSocket,Max_Chislo_Klients))
if (PotokMastExit) return 0;
slaveSocket[nomer_soketa]=WSAAccept(mainSocket,NULL,NULL,NULL,0);
if (PotokMastExit) return 0;
if (slaveSocket[nomer_soketa]==INVALID_SOCKET)
if (closesocket(mainSocket))
if (WSAAsyncSelect(slaveSocket[nomer_soketa],MainHandle,WM_TRANSACT,FD_READ || FD_CLOSE))
SocketUsed[nomer_soketa]=TRUE;
Massiv_Klients[nomer_soketa].Klient_To_Server=Massiv_Klients[nomer_soketa].Server_To_Klient=
Massiv_Klients[nomer_soketa].Byte_From_Klient_Soket_Service=
Massiv_Klients[nomer_soketa].Byte_From_Klient=0;
EventTotal[nomer_soketa]=0;
EventArray[nomer_soketa][EventTotal[nomer_soketa]] = WSACreateEvent();
ZeroMemory(&AcceptOverlapped[nomer_soketa], sizeof(WSAOVERLAPPED));
AcceptOverlapped[nomer_soketa].hEvent = EventArray[nomer_soketa][EventTotal[nomer_soketa]];
DataBuf[nomer_soketa].len = DATA_BUFSIZE;
DataBuf[nomer_soketa].buf = buffer[nomer_soketa];
RecvBytes[nomer_soketa]=BytesTransferred[nomer_soketa]=CallBack[nomer_soketa]=
Flags[nomer_soketa]=0;
EventTotal[nomer_soketa]++;
DataBuf[nomer_soketa].len = DATA_BUFSIZE;
DataBuf[nomer_soketa].buf = buffer[nomer_soketa];
Schitano[nomer_soketa]=true;
KolvoUsedSockets++;
if (nomer_soketa==Max_Chislo_Klients-1) nomer_soketa=0;
else nomer_soketa++;
m1:
if (SocketUsed[nomer_soketa]==TRUE)
<
if (nomer_soketa==Max_Chislo_Klients-1) nomer_soketa=0;
else nomer_soketa++;
goto m1;
>
//PostMessage(MainHandle,WM_PAINT,0,0);
m2:
if (KolvoUsedSockets==Max_Chislo_Klients)
<
Sleep(1000);
goto m2;
>
goto start;
return 0;
>
DWORD WINAPI SessionThread( LPVOID lpParam )
<
//lpParam у нас будет номер сокета
SOCKET socket = (SOCKET) lpParam;
// Тут логика работы твоего приложения с клиентом
closesocket(socket);
return 0;
>
UINT Potok(LPVOID pParam)
<
SOCKADDR_IN saddr;
WSADATA data;
SOCKET mainSocket=INVALID_SOCKET;
SOCKET slaveSocket=INVALID_SOCKET;
HANDLE dwThread;
if (WSAStartup(0x202,&data))
<
Fl_Err=2;
return 0;
>
mainSocket = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
if (mainSocket==INVALID_SOCKET) Fl_Err=3;
else
<
saddr.sin_family=AF_INET;
saddr.sin_addr.S_un.S_addr=INADDR_ANY;
saddr.sin_port=htons(PortServer);
int optval = 1;
int rc;
rc = setsockopt(mainSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval));
if (bind(mainSocket,(PSOCKADDR) &saddr,sizeof(SOCKADDR_IN)))
<
DWORD mmm999=GetLastError();
Fl_Err=3;
PotokMastExit = true;
>
Fl_Err=1;
if (listen(mainSocket,Max_Chislo_Klients))
<
Fl_Err=3;
PotokMastExit = true;
>
while (!PotokMastExit)
<
slaveSocket = WSAAccept(mainSocket,NULL,NULL,NULL,0);
if (slaveSocket != INVALID_SOCKET)
<
dwThread = CreateThread(NULL, 0, SessionThread, (void *)slaveSocket, 0, &dwThread);
CloseHandle(dwThread); // Закрываем хендл нити, так как с серверной части он нас больше не интересует
>
>
closesocket(mainSocket);
>
WSACleanup();
return 0;
>
спасибо, попробую завтра разобраться на свежую голову.
Добавлено через 7 часов, 18 минут и 52 секунды:
Попробовал.
Согласен с тем, что Вы более изящно оформили код в плане обработки ошибок.
Но в том то и дело, что их нет — даже когда связь валится — соединения с клиентом происходят нормально, т.е. в ветви обработки ошибок программа не попадает.
Принципиальное отличие только в том, что Вы создаете отдельный поток на каждого подключенного клиента. Для меня это не нужно да и нежелательно. Т.к. ожидание соединений вынесено в поток, то обработчик событий в сокетах я оставил в самом классе. И он один.
Так что где у меня неправильная логика — не понимаю. И потом, все это не объясняет почему возможен только 101 перезапуск (удаление и создание вновь) класса связи.
Зачем например закрывать главный сокет? А потом его заново пересоздавать? В моем коде он создается один раз. И до тех пор пока приложение не будет закрыто. Кстати, та логика, что я привел. Это стандартная логика серверных приложений. В твоей логике. Если например клиент начнет тупить, и не отсылать запрос сразу. Сервер повиснит и не будет принимать последуюшие запросы. Т.е убить твое приложение можно просто, открыть соединение и держать его открытым.
И кстати эти return 0 везде по коду, явная утечка. Текут у тебя зомби-сокеты.
Зачем например закрывать главный сокет? — Честно? А фиг его знает. Даже не задумывался.
Совет дельный — сейчас переделаю, но не совсем как ты предлагаешь — просто в своем коде перенесу метку
start:
к коду
slaveSocket[nomer_soketa]=WSAAccept(mainSocket,NULL,NULL,NULL,0);
Насчет «клиент начнет тупить» — проверено неоднократно — ничего не виснет. Серверу пофиг на этого клиента. Все работает с остальными дальше.
Выяснил еще один интересный факт. Сейчас усиленно гоняю приложение в режиме постоянных перезапусков класса связи и обнаружил, что ИНОГДА:
1. Перезапускаю класс связи. Ни одна из функций класса сервера НЕ возвращает ошибку.
2. netstat -n НЕ показывает что на таком-то порту что-то кем-то слушается.
3. клиент естественно говорит — сервер не найден.
4. после нескоьких(1-n) перезапусков все работает опять.
По этому поводу наткнулся на
там описаны параметры
У меня их в реестре нет. Может создать?
Добавлено через 3 минуты и 16 секунд:
Да, а насчет потоков и дескрипторов — пытаюсь понаблюдать, но толку мало — в приложении десятка 2 потоков, все постоянно «шевелится» и уловить что-то трудновато. Но устойчивого роста какого-либо показателя нет.
А виртуальная память вообще подупала :-).
да немного штук 40 мне пока хватит, просто некоторые клиенты очень специфичны и считать их в нагрузке один к одному нельзя.
Я думал про другое — там указан максимальный порт в системе 5000. У меня в реестре таких параметров нет, а порт как раз 5001.
Ну и время когда сокет в TIME_WAIT я бы сократил ниже плинтуса. Кстати вопрос до скольки? Сеть локальная, клиентов с инета нет.
Ты не правильно понял. Это не максимальный порт. А количество открытых портов одновременно. Т.е. это количество открытых соединений одновременно. Например порт у аськи 5190. А на твоей стороне порт обязательно будет выше 32536. Кстати настоятельно не рекомендуется открывать порты на прослушивание выше чем 32536. Порты от 32536 и до 65535 предназначены для автоматической биндовки.
Кстати обрати внимание на return 0 в своем коде. Почти всегда это чревато не закрытием сокетов у тебя.
MaxUserPort — максимально доступный открываемый № порта, по умолчанию 5000.
как раз написано порт пользователя, а не используемые (USED). Ну да это не важно и без них все работает до определенного момента.
Сокеты закрываются в деструкторе класса.
согласен. Туговато у меня с логикой ООП. И всякие «goto» тоже не есть гуд. Но т.к. первый язык был ассемблер — никак не могу переучиться.
Добавлено через 9 минут и 28 секунд:
>Просто на клиенте открой соединение. И ничего не посылай серверу.
Попробовал. Все отлично работает — следующий спокойно цепляется и работает, а тестовый так и висит, пока сервер его сам не прибьет по другим факторам.
Добавлено через 4 часа, 30 минут и 51 секунду:
to Finch
> поотключал все что смог — счетчик дескрипторов подрастает.
>С ейчас переделаю по твоему совету, а заодно добавлю параметров в реестр, а затем снова погоняю.
Реестр пока решил для чистоты эксперимента не трогать.
Погонял. Решились (кажется) 2 проблемы сразу — счетчик дескрипторов расти перестал.
И перестала уменьшаться выделенная приложению память — раньше сползала с 600 до 300 мб.
Сейчас попробую повключать нагрузки сколько смогу, а на рабочей системе запущу в понедельник.
Добавлено через 19 дней, 5 часов, 58 минут и 44 секунды:
Еще раз спасибо!
Проблема решена. Сервер проработал 2 недели вывалившись по совершенно иной причине.
Вот только сомнения остались — в чем была причина. Что «крамольного» в закрытии и открытии главного сокета вновь, что приводило к таким последствиям?
Но в принципе тема закрыта.
Делай проверки, лови исключения. Отладить по фотографии нельзя.
Серверный сокет вполне можно закрыть. Открывая его вновь не забудь REUSE.
Про фотографии я в курсе :-). Пока рою землю.
Дело в том что сервер работает под отладчиком — и никаких проблем не возникает — студия не ругается ни на что.
REUSE — поподробнее можно?
У меня при детекте потери связи класс отвечающий за связь уничтожается и создается заново. Единственное что до меня дошло — надо попробовать делать WSACleanup и затем WSAStartup. Но этот вариант означает — есть грабли в библиотеке WSA. В подтверждение этого
Не кто не сталкивался с заплатками от MS для WinSocket?
Система не отвергает. т.е. что до перезапуска класса связи сервера, что после клиенты подключаются. А вот команды не ходят. Так что bind не причем.
Добавлено через 47 минут и 9 секунд:
Обнаружил еще интересную фишку. В диспетчере задач приложение жрет гиг памяти и 1,5 виртуальной. Память у меня программа берет при старте и отдает в конце работы. А в диспетчере задач через какое-то(произвольное) время вместо гига появляется 420 мегабайт. При этом все еще несколько часов продолжает работать.
Добавлено через 1 день, 11 часов и 59 секунд:
Всем спасибо, думаю что тему можно закрывать. Перенес программу на старый сервер — все работает — память из программы не пропадает. Видимо что-то в ОС.
Добавлено через 47 дней, 10 минут и 59 секунд:
Как оказалось дело не совсем в винде. Или в какой-то комбинации — так и не пойму.
Есть сервер где программа работает уже 3 года месяцами (иногда по нескольку — как новая версия появится).
Но сколько не беру новых серваков с теми же дистрибутивами везде получаю одно и тоже. Через сутки выделение памяти падает с 1,1 Гб, до 400 Мб а затем падает библиотека WSA. Если ее перезапустить, заново создать класс отвечающий за связь — все работает.
Стал копать дальше. Методом глубоко научного тыка выяснил что все сводится к одному блоку кода. Данный код работает в потоке. Поток запускается раз в 10 минут, отрабатывает примерно 1-2 минуты и закрывается. Код того места в потоке где возникает ошибка
if (CopyFile(FileNameIst,FileNamePri,false)==0)
m_pUkaz->StrPotok2=»Ошибка копирования файла «+str1.Mid(1,str1.GetLength())+» .»;
else m_pUkaz->StrPotok2=»Файл «+str1.Mid(1,str1.GetLength())+» скопирован.»;
Вариантов остается 2 — либо проблемы из-за функции CopyFile, либо из-за операций со строками. Сейчас выясняю. Но логичного объяснения пока так и не нахожу. Идеи есть?
и синхронизировать конечно же надо
Mikl, тут дело вот в чём. Код ты не показывал, поэтому никто не может точно сказать, какой именно объект нуждается в синхронизации. И даже если ты покажешь код, и если он будет объёмный — никто рыться в нём не будет.
Признаки, когда требуется синхронизация, уже были указаны — тогда, когда есть любая отличная от нуля вероятность того, что по строчке кода с общим ресурсом может пробежаться одновременно более , чем один поток.
Синхронизация вводится для того, чтобы свести эту вероятность к нулю.
Предполагаю, что ты уже читал и работал с синхронизацией, но если это не так, то, на всякий случай, вот:
к примеру, в ОС Windows для этого используется критическая секция, которая оборачивает защищаемый (синхронизируемый) участок кода. Работает это так:
S — объект для синхронизации (хендл критической секции)
O — защищаемый ресурс
а во всех потоках есть в начале вызов AfxSocketInit() ?
(говорю только за MFC, ибо упомянут CString. Для АПИ это вроде WSAStartup )
Нету их. Как ни бредово звучит но.
Сокеты на клиентах открываются, первую команду клиент отсылает, но сервер ее не получает.
Добавлено через 13 часов, 19 минут и 38 секунд:
первая половина эксперимента закончена. Со строками проблем нет. Осталось выяснить с CopyFile.
Добавлено через 1 день, 23 часа, 35 минут и 10 секунд:
Выяснил. Дело именно в CopyFile. Причем т.к. функция выполняется от неск. секунд до минуты для каждого файла (их около 10), то видно что во время ее работы при подключении новых клиентов сокращается выделение памяти.
Есть какие нибудь идеи?
У меня только одна — в функция CopyFile я передаю в качестве параметров объекты типа CString, создаваемые внутри потока. Может создавать их в классе, который вызывает поток?
Добавлено через 1 день, 5 минут и 42 секунды:
Идея не удалась.
Увы, я не знаю что это такое.
Еще пару дней «плясок с бубном» и просто выкину эту функцию из программы сделав вынос ее во внешнее приложение.
Попробую объяснить подробнее.
Для теста сделано что клиенты подключаются к серверу, получают пол мегабайта данных и отключаются. Делается это весьма быстро.
Если не работает поток в котором вся проблема — то все работает замечательно.
Поток выполняется функция CopyFile запускается раз в 10 минут для копирования файлов из одного места в другое.
Перед началом копирования каждого файла (их около 10) выводится на экран строка «Копирование файла. » и выполняется функция CopyFile.
По окончании работы функции выводится сообщение об успешном или неудачном завершении копирования файла.
Так вот при подключении новых клиентов в интервале когда работает CopyFile, т.е. между выводами сообщений, наблюдается снижение выделенной памяти на несколько килобайт.
Как по другому объяснить я не знаю. И причину тоже понять не могу.
этот класс в скольких экземплярах создается?
согласен с RXL, прислушайтесь
Класс создается в одном экземпляре.
RXL естественно прав. Согласен что дело не в том как работает функция. Дело в том откуда она вызывается.
CopyFile править не думаю по одной причине — на рабочем серваке все работает уже 4 года.
По делу.
Попытка выноса функционала потока во внешний экзешник и пинание его из потка когда надо ни к чему не привела. Вызов Функции ShellExecute приводит к тому же самому. Пока идей нет — буду думать дальше как время появится.
«Я . дорогая редакция» (С)
Путем долгих экспериментов решение проблемы было найдено. Однако причина так и осталась неясна.
Сначала Я вынес функционал по копированию в отдельное приложение, которое запускалось из главного при старте. Не помогло.
Потом я стал это приложение запускать руками. Не помогло.
Дальше пошли совсем уже пляски с бубном. Решилось все элементарно. Если функция копирования в качестве приемника использует диски этой же машины — через 1-3 сутки в приложении сервера начинается падение выделения памяти. Почему пока не разобрался. Но, если копирование осуществляется на сетевой ресурс — все работает без проблем.
Буду разбираться дальше. После выноса всего функционала по копированию в отдельное приложение синхронизация между этим приложением и серверным осуществляется только по файлу-флагу. Если его удается создать заново в приложении, значит база свободна и можно с ней работать. Осуществляется это следующим кодом (одинаковым везде)
try
HANDLE FileHandleName=CreateFile(m_pUkaz->FileFlagNameDB, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_DELETE,NULL,CREATE_NEW,FILE_ATTRIBUTE_HIDDEN,NULL);
if (FileHandleName!=INVALID_HANDLE_VALUE)
/блокирующий>.
>
CloseHandle(FileHandleName);
при этом FileFlagNameDB=»\\\\server\\Baza\\TaxiDB.flg»
Так что осталось попробовать поотключать эти блоки или попробовать сделать имя файла локальным.
Чем правильно ловить MFC-шные эксепшены:
http://msdn.microsoft.com/en-us/library/e583tzca(v=VS.80).aspx
А если ловить при помощи try-catch, то случается утечка памяти.
Добавлено через 33 минуты и 13 секунд:
Если я правильно понял то MFC-шные эксепшены надо ловить с помощью TRY, а не try как у меня?
Но в http://forum.sources.ru/index.php?showtopic=49090 написано
«Вопрос. В Visual C++ я видел операторы try и TRY. В чём отличие и чем лучше пользоваться?
Макросы TRY/CATCH/AND_CATCH/END_CATCH/THROW/THROW_LAST тянутся из тех времен, когда компилятор C++ от MS еще не поддерживал стандартную обработку исключений. Пользоваться ли ими – это уже ваш выбор, но в свете сказанного ранее – не советую.»
И потом DeleteFile не относится к MFC вроде как? Или CFileException заменить на .
Mikl, я не знаю, на чём основана уверенность (вернее — неуверенность) товарисча Бобра. Но я уже сказал, что будет происходить (я прочувствовал это с исключениями CDBException): объект класса, описывающего исключение, создаётся где-то в глубине классов MFC оператором new, выбрасывается. Если ты его ловишь catch , то никак не производишь возвращение памяти в кучу. С макросами это произойдёт автоматом.
Кроме того, я не знаю, это ли причина у тебя, но по симптомам очень похоже, особенно если исключение часто возникает. Непонятен ещё один момент — как это исключение вообще может произойти в АПИшной функции 🙂
Тебе тут вообще не нужны исключения, обрабатывай ошибки (GetLastError())
>Тебе тут вообще не нужны исключения, обрабатывай ошибки (GetLastError())
Согласен. Обернуто в исключения по принципу «кашу маслом не испортишь».
ну теперь хотя бы есть с чем экспериментировать дальше.
там вообще try не нужно, по идее. И TRY тоже
ну а ошибка не обязательно тут
Добавлено через 2 минуты и 23 секунды:
пообращай внимание на данные, которые отображает диспетчер задач, повключай все интересные колонки — сколько дескрипторов, сколько потоков, память, объекты GDI и прочее. Последи за их динамикой
Источник