Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.73/48: Рейтинг темы: голосов - 48, средняя оценка - 4.73
1 / 1 / 1
Регистрация: 14.03.2014
Сообщений: 46
1

Server Socket, Asynchronous socket error 10053

08.07.2014, 11:50. Показов 9067. Ответов 18
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Всем привет. Сразу к делу. Работаю с компонентом ServerSocket, при приеме данных возникает asynchronous socket error 10053.
Сервер работает в режиме stNonBlocking, клиент - постоянно посылает какую-то информацию. Задача - принять и обработать. Интервал между посылками, примерно 20ms а размер пакета 150 байт.

C++
1
2
std::vector <unsigned char> dataAll; //приемный контейнер
BYTE buf[2000];                 //переменный буфер
C++
1
2
3
4
5
6
7
8
void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
      TCustomWinSocket *Socket)
{
        length = ServerSocket1->Socket->Connections[0]->ReceiveLength();
        ServerSocket1->Socket->Connections[0]->ReceiveBuf(buf, length);
        dataAll.resize(dataAll.size() + length);
        memcpy(&dataAll[dataAll.size() - length], &buf, length);
        lengthAll+=length; Form1->Edit2->Text = lengthAll;
Принимаю в контейнер, таким вот способом, по событию чтения клиента. Так вот, открываю порт, слушаю, жду connect'a, пока все в порядке. Но как только клиент подключается, он сразу же начинает забрасывать потоком данных и не успев принять, возникает error 10053.
Какие есть варианты? Быть может прописать что-то в OnClientError, помимо ErrorCode = 0.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
08.07.2014, 11:50
Ответы с готовыми решениями:

Asynchronous socket error 10060
Добрый день. Я делаю программу с использованием Socket. Вот код сервера....

Ошибка: Asynchronous socket error 10061
Делаю клиент и сервер с помощью компонентов TClientSocket и TServerSocket. На одной машине все...

Server(Client)Socket
Всем привет. Собираюсь сделать передачу команд между сервером-клиентом через socket'ы, но возник...

Client и Server Socket
Доброго дня суток , подскажите как можно переслать , к примеру , с клиента на сервер 2 переменные ,...

18
742 / 530 / 132
Регистрация: 31.05.2013
Сообщений: 3,011
Записей в блоге: 3
08.07.2014, 14:29 2
Скорее всего не хватает выделенной памяти на прием в Вашем "контейнере"
0
1 / 1 / 1
Регистрация: 14.03.2014
Сообщений: 46
08.07.2014, 17:41  [ТС] 3
Так Вектор в том-то и дело что сам наращивается и ему все равно какой длинны он будет, пока не займет в теории всю оперативную память компьютера.
Другое дело что массив в векторе в памяти идет как бы подряд и если какой-то участок памяти на его доблестном разрастании занят, то он переносит весь вектор в новый участок плюс резервирует место, при каждом наращивании все больше и больше.
Проблема в том что как только клиент присоединяется, моментально вылетает ошибка или вовсе программа убивается виндой. Не понимаю почему так.

Добавлено через 2 часа 21 минуту
Попробовал стандартный чатик из Examples в builder. Все великолепно принимает, простой как палка.

C++
1
2
3
4
5
void __fastcall TChatForm::ServerSocketClientRead(TObject *Sender,
      TCustomWinSocket *Socket)
{
  Memo2->Lines->Add(Socket->ReceiveText());  
}
Опять же проблема значится в алгоритме записи моем. У кого есть какие идеи как записать, если не с помощью вектора. В принципе, мне ведь все равно, идут данные подряд в памяти или нет. Можно использовать и контейнеры с указателем на следующую ячейку. Может повозиться с динамическим буфером, второй побольше создать, туда перенести, как заполнен первый а потом удалить его. Есть-какие предложения?
Или использовать ReceiveText, загонять в string, а после уже разбивать как захочу?
Но разве это из-за ReceiveBuf() запара? Или все-таки с вектором перемудрил?
0
742 / 530 / 132
Регистрация: 31.05.2013
Сообщений: 3,011
Записей в блоге: 3
08.07.2014, 18:13 4
можно попробовать так

C
1
2
3
int len = ServerSocket1->Socket->ReceiveLength();
char* buf= new char[len+1];
ServerSocket1->Socket->ReceiveBuf((void*)buf, len);
1
91 / 91 / 22
Регистрация: 02.07.2013
Сообщений: 332
09.07.2014, 10:21 5
Dinkin, прежде, чем ковыряться в коде, имеет смысл ознакомиться с самой ошибкой. 10053 означает "удалённый компьютер закрыл подключение". Из-за чего-то. Т.е., при попытке доступа к сокету, соединение уже разорвано. Думаю, надо смотреть клиента...
0
742 / 530 / 132
Регистрация: 31.05.2013
Сообщений: 3,011
Записей в блоге: 3
09.07.2014, 11:46 6
Цитата Сообщение от c0rvax Посмотреть сообщение
смысл ознакомиться с самой ошибкой. 10053 оз
Так он же пишет, что при нормальной отправке данных все норм...а данная ошибка в основном распространяется на сервер, который закрывает соединение, если что-то не успел/не смог обработать по какой-либо причине.
0
91 / 91 / 22
Регистрация: 02.07.2013
Сообщений: 332
09.07.2014, 12:03 7
Dinkin, можешь, конечно, остаться при своих. А можешь показать код, как происходит отправка. Или хотя бы сделай предварительную проверку, активно ли подключение
C++
1
2
3
4
if( ServerSocket1->Socket->Connections[0]->Connected )
{
  ...
}
0
742 / 530 / 132
Регистрация: 31.05.2013
Сообщений: 3,011
Записей в блоге: 3
09.07.2014, 13:05 8
так я то че, не мне же помогать,с меня за чем код?) а парень свой код выше показал, при каких случаях у него ошибка
0
1 / 1 / 1
Регистрация: 14.03.2014
Сообщений: 46
10.07.2014, 11:03  [ТС] 9
Клиент, это плата, подсоединенная к чипу Withnet Ethernet W5100, она просто кидает connect и если сервер отвечает, начинает забрасывать данные. Дело в том что другая прога, которую я писал на Delphi, работает, хотя в builder'e сделал все аналогично, за исключением вектора. Там был статический буфер, набиваемый до конца, а после закрывающий соединение. И еще, как я понял Indy server работает в Thread blocking а Server socket в nonBlocking.
Теперь же задача стоит в том, что мы не знаем сколько будет данных, поэтому и вектор. Плата шлет огромное количество попыток connect() и как только получает ответ, начинает кидать данные.

C++
1
2
3
4
5
6
7
8
void __fastcall TForm1::ServerSocket1ClientConnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
        mLog->SelAttributes->Color = clBlue;
        mLog->Lines->Add("[" + TimeToStr(Time()) + "] подключен: " + ServerSocket1->Socket->Connections[0]->RemoteAddress);
        Edit1->Text = Form1->ServerSocket1->Socket->Connections[0]->RemoteAddress;
 
}
Особенность только в работе с платой, но дело ведь в том что на другой проге все ок, а с этими сокетами ошибки лезут вот такие.

Добавлено через 5 минут
И я тут подумал, если попыток connect'а много, пока сеть обнаружится, все дела, ведь до подачи питания на плату, сети-то и нет. Так вот, приходит сразу 10 коннектов, у меня не предусмотрена работа с несколькими соединениями. Сервер видит их как много клиентов и открывает столько потоков, сколько пришло connect(). А после и ложится, ибо я работаю только с Connections[0]. Больше не предусмотрел, все равно клиент всегда один.
В ThreadBlocking все идет одним потоком и ему до лампочки сколько connect() он получил. Начал, отработал и дисконнектнул клиента.
0
91 / 91 / 22
Регистрация: 02.07.2013
Сообщений: 332
10.07.2014, 12:24 10
Zerorc, ну, какие мысли. Во-первых, "буфер, набиваемый до конца, а после закрывающий соединение" - это уже неправильно. Соединение не следует закрывать, пока программа работает. Общая логика такова: открыли один раз соединение, набиваем буфер, набили отправили, очистили буфер, снова набиваем. И ничего не закрываем, соединение всегда установлено. Практика показывает, что команда на закрытие соединения может придти гораздо быстрее, чем отправляемый буфер данных. И в тот момент, когда сервер начинает что-то пытаться читать из сокета, последний уже закрыт, а то и NULL. Отсюда и ошибка 10053 возникает "удалённый компьютер закрыл подключение".

Во-вторых, совершенно правильная мысль, что неверно обращаться к Connections[0]. Для того, чтобы серверу однозначно правильно что-то читать из сокетов, надо использовать передаваемый в событие OnClientRead параметр Socket, ибо это именно он готов отдать какие-то данные. А самих активных подключений [ServerSocket->ActiveConnections] может быть великое множество.
1
1 / 1 / 1
Регистрация: 14.03.2014
Сообщений: 46
10.07.2014, 12:37  [ТС] 11
Дело в том что так было в прошлой программе и все работало, теперь я не закрываю соединение, к тому же там буфер был действительно огромный и мог принять большой обьем информации. Знаю, что лучше в файл, потом очищать буфер, дописывать в файлик и тд.

Переделал код таким вот образом
C++
1
 int concnt = -1; //счетчик действующих клиентов. Глобально
C++
1
2
3
4
5
6
7
8
void __fastcall TForm1::ServerSocket1ClientConnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
         concnt++;
        mLog->SelAttributes->Color = clBlue;
        mLog->Lines->Add("[" + TimeToStr(Time()) + "] подключен: " + ServerSocket1->Socket->Connections[concnt]->RemoteAddress);
        Edit1->Text = Form1->ServerSocket1->Socket->Connections[concnt]->RemoteAddress;
}
C++
1
2
3
4
5
6
7
8
void __fastcall TForm1::ServerSocket1ClientDisconnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
        mLog->SelAttributes->Color = clGray;
        mLog->Lines->Add("[" + TimeToStr(Time()) + "] отключен: " + ServerSocket1->Socket->Connections[concnt]->RemoteAddress);
        GraphTimer->Enabled = false;
        concnt--;
}
C++
1
2
3
4
5
6
7
8
9
10
11
void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
      TCustomWinSocket *Socket)
{
        unsigned len = ServerSocket1->Socket->Connections[concnt]->ReceiveLength();
        BYTE* buf= new BYTE[len+1];
        ServerSocket1->Socket->Connections[concnt]->ReceiveBuf((char*)buf, len);
dataAll.resize(dataAll.size() + len);
        memcpy(&dataAll[dataAll.size() - len], buf, len);
        lenAll+=len; Form1->Edit2->Text = lenAll;
 
        delete buf;
что происходит. Пишет что клиент подключен, может и раз десять так написать, подряд и принимает какими-то промежутками данные. Все равно не то что нужно. Соединение не закрываю вообще.
0
91 / 91 / 22
Регистрация: 02.07.2013
Сообщений: 332
10.07.2014, 12:58 12
Лучший ответ Сообщение было отмечено Zerorc как решение

Решение

Я говорил про это
C++
1
2
3
4
5
6
7
8
9
10
11
void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
      TCustomWinSocket *Socket)
{
        unsigned len = Socket->ReceiveLength(); // сокет, который из параметров !!!
        BYTE* buf= new BYTE[len+1];
        Socket->ReceiveBuf((char*)buf, len);
dataAll.resize(dataAll.size() + len);
        memcpy(&dataAll[dataAll.size() - len], buf, len);
        lenAll+=len; Form1->Edit2->Text = lenAll;
 
        delete buf;
1
1 / 1 / 1
Регистрация: 14.03.2014
Сообщений: 46
10.07.2014, 13:49  [ТС] 13
Опа! А вот тут я не понял. Я беру получается, обращаясь к определенному соединению, которое, быть может, было когда-то но в данный момент его нет. И из-за этого ошибка 10053.

Но, когда я обращаюсь к активному соединению, посредством
C++
1
unsigned len = Socket->ReceiveLength(); // сокет, который из параметров !!!
то данные я гарантированно получу. Так?

C++
1
2
3
4
5
6
7
8
        unsigned len = Socket->ReceiveLength();
        BYTE* buf= new BYTE[len+1];
        Socket->ReceiveBuf((char*)buf, len);
        dataAll.resize(dataAll.size() + len);
        memcpy(&dataAll[dataAll.size() - len], buf, len);
        lenAll+=len; Form1->Edit2->Text = lenAll;
 
        delete buf;
0
91 / 91 / 22
Регистрация: 02.07.2013
Сообщений: 332
10.07.2014, 14:36 14
Connections[] - это все активные соединения сервера. Их может быть несколько, что понятно. На то он и сервер. Допустим их 10. И тут один из клиентов, скажем 5-й, присылает данные. Читать надо данные именно из этого сокета, а не из какого-то определённого. Для этого на него и передаётся в событийную функцию ссылка.
0
1 / 1 / 1
Регистрация: 14.03.2014
Сообщений: 46
10.07.2014, 14:41  [ТС] 15
Ага, все понятно. Я читал всегда с 0 соединения что в принципе было правильно, ибо клиент один и доколе соблюдение протокола оказывалось филигранным, так сказать, касаемо двух ПК, к примеру.
Но самопальная программа, которая посылает коннект пару сотен раз и может оказаться на любом Connections[?] имела все это ввиду.
И если я читаю
данные именно из этого сокета, а не из какого-то определённого
, то все в порядке)
0
91 / 91 / 22
Регистрация: 02.07.2013
Сообщений: 332
10.07.2014, 15:09 16
С 0 соединения можно читать, если клиент однозначно один и он регулярно не закрывает подключение. Допустим клиент отправил данные и закрыл подключение, а потом подключился ещё раз, чтобы ещё раз отправить. Так как всё это дело выполняется в некоем потоке, то вполне возможен вариант, что "старый", неиспользуемый уже сокет ещё не удалён из Connections[], ActiveConnections будет равен 2 и очередную порцию данных надо будет читать из Connections[1].
0
1 / 1 / 1
Регистрация: 14.03.2014
Сообщений: 46
10.07.2014, 15:15  [ТС] 17
Тогда правильный ли вариант с отправкой этому клиенту сообщения, если он регулярно может сбросить соединение, к примеру, после снова подключиться. Если я все правильно понял..

C++
1
2
3
4
5
void __fastcall TForm1::Button3Click(TObject *Sender)
{
... //проверки есть ли соединение, во избежание вылетов
Form1->ServerSocket1->Socket->Connections[ServerSocket1->Socket->ActiveConnections-1]->SendBuf(buff,100);
}
Я не могу считать событие ибо событие у меня здесь - это нажатие кнопочки. Единственный выход?
0
91 / 91 / 22
Регистрация: 02.07.2013
Сообщений: 332
10.07.2014, 15:36 18
Я бы не так сделал. Во-первых, нет никакой гарантии, что активным является именно последний сокет из всех имеющихся. К тому же, придерживаюсь идеологии, что если сервер что-то отправляет, то надо отправлять всем клиентам. Раз все клиенты подключаются к одному серверу, то каждому надо как-то получать результаты работы других. Тот же чат, например. Один сказал, а всем пришло. Во-вторых, совершенно верно, необходимо убедиться, что подключение активно. Поэтому, чтобы убить всех зайцев, я бы посоветовал такую реализацию
C++
1
2
3
4
5
6
7
8
9
10
11
void __fastcall TForm1::Button3Click(TObject *Sender)
{
  for( int i = 0; i < ServerSocket1->Socket->ActiveConnections; i++ )
  {
    TCustomWinSocket* ASocket = ServerSocket1->Socket->Connections[ i ];
    if( ASocket && ASocket->Connected )
    {
      ASocket->SendBuf( buff, 100 );
    }
  }
}
1
1 / 1 / 1
Регистрация: 14.03.2014
Сообщений: 46
10.07.2014, 15:51  [ТС] 19
Неплохо. Но это тогда выйдет широковещательная посылка. А если, я, к примеру, даю модулю команду отключиться. В принципе, если известен IP, его можно вытащить и по нему выбрать соединение, сравнением, пройтись по всем и отправить нужному.
Но это уже темка для отдельной статьи. С асинхроном разобрался. Спасибо за помощь.
0
10.07.2014, 15:51
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
10.07.2014, 15:51
Помогаю со студенческими работами здесь

Socket Error # 10061
привет всем. У меня проблема. Добавил IdFTP. Написал в билдере: void __fastcall...

Socket error 11001
Вот если нету соединения с нетом, то вылетает ошибка socked error 11001. Можно ли как-нибудь её...

Socket Error # 10048
Добрый день. У меня при использовании компонентов TMNFTP, TIdFTP, TIdHTTPServer при ввода команды ...

Indy 10 (socket error # 10061)
Доброго! Ни как не могу отловить ошибку отсутствия сервера, что бы просто говорила, что его нет.


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

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru