Отправка данных через сокет в блокирующем режиме
От: vers  
Дата: 01.05.07 19:05
Оценка:
Имеется сокет, socket.Blocking = true, однако, при отправке сколько угодно большого количества данных операция отправки завершается моментально, не дожидаясь приема всех данных сервером, хотя MSDN пишет: "If you are in blocking mode, and you make a method call which does not complete immediately, your application will block execution until the requested operation completes."
Код:
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ep = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 1999);
socket.Blocking = true;
socket.Connect(ep);
byte[] buf = new byte[100000000];
int bytesSent = bytesSent = socket.Send(buf);
MessageBox.Show(bytesSent.ToString());

IP-адрес 192.168.0.1 — не локальный.
С приемом данных то же самое, приходиться крутить socket.Receive в цикле, пока она не примет все данные.
Re: Отправка данных через сокет в блокирующем режиме
От: SergeyT  
Дата: 07.05.07 13:40
Оценка:
Здравствуйте, vers, Вы писали:

V>Имеется сокет, socket.Blocking = true, однако, при отправке сколько угодно большого количества данных операция отправки завершается моментально, не дожидаясь приема всех данных сервером, хотя MSDN пишет: "If you are in blocking mode, and you make a method call which does not complete immediately, your application will block execution until the requested operation completes."


Прочтите внимательно документацию: The successful completion of a send does not indicate that the data was successfully delivered. If no buffer space is available within the transport system to hold the data to be transmitted, send will block unless the socket has been placed in nonblocking mode.

А для того чтобы удостовериться что данные действительно дошли, пусть получатель пришлет подтверждение о приеме.
Re[2]: Отправка данных через сокет в блокирующем режиме
От: vers  
Дата: 07.05.07 15:39
Оценка:
V>>Имеется сокет, socket.Blocking = true, однако, при отправке сколько угодно большого количества данных операция отправки завершается моментально, не дожидаясь приема всех данных сервером, хотя MSDN пишет: "If you are in blocking mode, and you make a method call which does not complete immediately, your application will block execution until the requested operation completes."

ST>Прочтите внимательно документацию: The successful completion of a send does not indicate that the data was successfully delivered. If no buffer space is available within the transport system to hold the data to be transmitted, send will block unless the socket has been placed in nonblocking mode.


ST>А для того чтобы удостовериться что данные действительно дошли, пусть получатель пришлет подтверждение о приеме.


Да, действительно. А если данных 100 мегабайт? Пока получатель пришлет подтверждение, у клиента таймаут наступит. Можно, конечно, разбить сообщение на маленькие блоки, только вот я не знаю пропускной способности сети, на которой будет работать приложение, да и накладные расходы возрастают. И еще: а если в процессе передачи возникнет ошибка? Ждать пока на клиенте таймаут ожидания подтверждения наступит? Как-то ненадежно все это...
Почитал книжку ".NET. Сетевое программирование для профессионалов." Ни слова об обработки ошибок во время передачи данных нет. А ведь сокет на каждый TCP-пакет посылает ACK-пакет подтверждения. Неужели сложно было реализовать обработку этих пакетов в .NET...
FTP-клиенты же как-то ловят ошибки во время передачи файлов на сервер, хотя сервер никаких подтверждений во время передачи не клиенту не отправляет (кроме ACK, естественно).
Re[3]: Отправка данных через сокет в блокирующем режиме
От: SergeyT  
Дата: 08.05.07 08:19
Оценка:
Здравствуйте, vers, Вы писали:

V>Да, действительно. А если данных 100 мегабайт? Пока получатель пришлет подтверждение, у клиента таймаут наступит.


Таймаут наступит только в том случае если произойдет обрыв сетевого соединения (умер получатель, или вынули сетевой кабель), тогда сам стек протоколов TCP/IP попробует несколько раз повторить передачу потерянного пакета и не получив подтверждения от принимающей стороны выдаст ошибку. А пока данные успешно передаются таймаут не сработает, если конечно вы не установите значение Socket.SendTimeout в ненулевое значение .

Можно, конечно, разбить сообщение на маленькие блоки, только вот я не знаю пропускной способности сети, на которой будет работать приложение, да и накладные расходы возрастают. И еще: а если в процессе передачи возникнет ошибка? Ждать пока на клиенте таймаут ожидания подтверждения наступит? Как-то ненадежно все это...

Идея разбить сообщение на маленькие блоки, с подтверждением после каждой переданной порции, не лишена смысла, тогда не придется ожидать пока освободится буфер стека TCP. Размер порции можно сделать 1 килобайт, тогда она точно поместится в один TCP пакет.

V>Почитал книжку ".NET. Сетевое программирование для профессионалов." Ни слова об обработки ошибок во время передачи данных нет. А ведь сокет на каждый TCP-пакет посылает ACK-пакет подтверждения. Неужели сложно было реализовать обработку этих пакетов в .NET...


Сокеты в .NET построены на базе WinSocks, поэтому все подтверждения реализованы, иначе это был-бы уже не TCP/IP
Re[4]: Отправка данных через сокет в блокирующем режиме
От: vers  
Дата: 08.05.07 08:49
Оценка:
V>>Да, действительно. А если данных 100 мегабайт? Пока получатель пришлет подтверждение, у клиента таймаут наступит.

ST> Таймаут наступит только в том случае если произойдет обрыв сетевого соединения (умер получатель, или вынули сетевой кабель), тогда сам стек протоколов TCP/IP попробует несколько раз повторить передачу потерянного пакета и не получив подтверждения от принимающей стороны выдаст ошибку. А пока данные успешно передаются таймаут не сработает, если конечно вы не установите значение Socket.SendTimeout в ненулевое значение .


ST> Идея разбить сообщение на маленькие блоки, с подтверждением после каждой переданной порции, не лишена смысла, тогда не придется ожидать пока освободится буфер стека TCP. Размер порции можно сделать 1 килобайт, тогда она точно поместится в один TCP пакет.


Тогда такой чисто теоретический вопрос: предположим, что я программирую FTP-клиент, в таком случае как мне отображать прогресс передачи данных? Даже, если это будет асинхронная передача, нигде не указывается, сколько байт в текущий момент уже передано. Либо "передача идет", либо "уже передано".
Re[5]: Отправка данных через сокет в блокирующем режиме
От: SergeyT  
Дата: 08.05.07 12:52
Оценка:
Здравствуйте, vers, Вы писали:

V>Тогда такой чисто теоретический вопрос: предположим, что я программирую FTP-клиент, в таком случае как мне отображать прогресс передачи данных? Даже, если это будет асинхронная передача, нигде не указывается, сколько байт в текущий момент уже передано. Либо "передача идет", либо "уже передано".


При создании сокета установить
Socket.SendBufferSize = 65536;
При передаче разбить файл на куски по 16384 байт и передачу следующей порции начинать только если
true == Socket.Poll(-1, SelectMode.SelectWrite)

В этом случае можно отображать прогресс. Размерами буфера и порций можно поиграться в зависимости от величины передаваемых данных.
Re: Отправка данных через сокет в блокирующем режиме
От: _Morpheus_  
Дата: 08.05.07 16:11
Оценка:
Здравствуйте, vers, Вы писали:

V>Имеется сокет, socket.Blocking = true, однако, при отправке сколько угодно большого количества данных операция отправки завершается моментально, не дожидаясь приема всех данных сервером, хотя MSDN пишет: "If you are in blocking mode, and you make a method call which does not complete immediately, your application will block execution until the requested operation completes."


V>С приемом данных то же самое, приходиться крутить socket.Receive в цикле, пока она не примет все данные.


все правильно, в документации речь идет о том что если весь блок данных не удалось поместить в буфер, то операция блокируется до момента когда буфер освободится и все отправляемые данные будут в него запихнуты
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[3]: Отправка данных через сокет в блокирующем режиме
От: _Morpheus_  
Дата: 08.05.07 16:14
Оценка:
Здравствуйте, vers, Вы писали:

V>>>Имеется сокет, socket.Blocking = true, однако, при отправке сколько угодно большого количества данных операция отправки завершается моментально, не дожидаясь приема всех данных сервером, хотя MSDN пишет: "If you are in blocking mode, and you make a method call which does not complete immediately, your application will block execution until the requested operation completes."


ST>>Прочтите внимательно документацию: The successful completion of a send does not indicate that the data was successfully delivered. If no buffer space is available within the transport system to hold the data to be transmitted, send will block unless the socket has been placed in nonblocking mode.


ST>>А для того чтобы удостовериться что данные действительно дошли, пусть получатель пришлет подтверждение о приеме.


V>Да, действительно. А если данных 100 мегабайт? Пока получатель пришлет подтверждение, у клиента таймаут наступит


подтверждение можешь не ждать — дождись когда освободится буфер и следующая порция уйдет в сеть, т.е. все данные переданные в Send будут помещены в буфер для отправк
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[5]: Отправка данных через сокет в блокирующем режиме
От: _Morpheus_  
Дата: 08.05.07 16:15
Оценка:
Здравствуйте, vers, Вы писали:

V>>>Да, действительно. А если данных 100 мегабайт? Пока получатель пришлет подтверждение, у клиента таймаут наступит.


ST>> Таймаут наступит только в том случае если произойдет обрыв сетевого соединения (умер получатель, или вынули сетевой кабель), тогда сам стек протоколов TCP/IP попробует несколько раз повторить передачу потерянного пакета и не получив подтверждения от принимающей стороны выдаст ошибку. А пока данные успешно передаются таймаут не сработает, если конечно вы не установите значение Socket.SendTimeout в ненулевое значение .


ST>> Идея разбить сообщение на маленькие блоки, с подтверждением после каждой переданной порции, не лишена смысла, тогда не придется ожидать пока освободится буфер стека TCP. Размер порции можно сделать 1 килобайт, тогда она точно поместится в один TCP пакет.


V>Тогда такой чисто теоретический вопрос: предположим, что я программирую FTP-клиент, в таком случае как мне отображать прогресс передачи данных? Даже, если это будет асинхронная передача, нигде не указывается, сколько байт в текущий момент уже передано. Либо "передача идет", либо "уже передано".



отправляй данные маленькими порциями, с таким расчетом чтобы они влазили в буфер (размер буфера зависит от сетевых настроек ОС, обычно около 4 КБ)
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[6]: Отправка данных через сокет в блокирующем режиме
От: unit132  
Дата: 18.03.08 22:12
Оценка:
Здравствуйте, SergeyT, Вы писали:

ST>Здравствуйте, vers, Вы писали:


V>>Тогда такой чисто теоретический вопрос: предположим, что я программирую FTP-клиент, в таком случае как мне отображать прогресс передачи данных? Даже, если это будет асинхронная передача, нигде не указывается, сколько байт в текущий момент уже передано. Либо "передача идет", либо "уже передано".


ST>При создании сокета установить

ST>Socket.SendBufferSize = 65536;
ST>При передаче разбить файл на куски по 16384 байт и передачу следующей порции начинать только если
ST>true == Socket.Poll(-1, SelectMode.SelectWrite)

ST>В этом случае можно отображать прогресс. Размерами буфера и порций можно поиграться в зависимости от величины передаваемых данных.



Проблема в том что Socket.Poll говорит о том что можно слать ещё, а не о том что всё что всё уже раньше отправлено. Для меня вопрос о том как отображать прогресс для аплоада остаётся открытым, т.к. при такой модели в Socket.Send могут уйти мегабайты за несколько секунд, а на стороне получателя скорость 1kb/s
Re[6]: Отправка данных через сокет в блокирующем режиме
От: unit132  
Дата: 18.03.08 22:14
Оценка:
Здравствуйте, _Morpheus_, Вы писали:

_M_>отправляй данные маленькими порциями, с таким расчетом чтобы они влазили в буфер (размер буфера зависит от сетевых настроек ОС, обычно около 4 КБ)


А как узнать что прошлая порция уже отправилась ?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.