Последние темы Поиск
Общие форумы
Форумы поддержки портала iXBT.com
Специализированные форумы
ПроцессорыРазгон и охлаждениеСистемные платыМодули памятиВидеосистемаКриптовалюты, майнинг, blockchain-технологии, NFTИскусственный интеллект: технологии, практика, развитиеTV- и FM-тюнеры, видеовход, видеовыходЦифровое видео: захват, монтаж, обработкаМониторы и другие устройства отображенияЦифровое фотоБеспилотные летательные аппаратыЦифровой звукProAudio: Профессиональное звуковое оборудованиеСтереосистемыДомашний кинотеатр: проигрыватели и источники сигналаДомашний кинотеатр: аудиосистемаДомашний кинотеатр: ТV и проекторыМагнитные и SSD накопителиОптические носители информацииСетевые носители информацииПериферияКорпуса, блоки питания, UPSСети, сетевые технологии, подключение к интернетуСистемное администрирование, безопасностьСерверыНоутбуки, нетбуки и ультрабукиПланшеты и электронные книгиМобильные телефоны, смартфоны, кпк, коммуникаторыМобильные гаджетыОператоры и технологии мобильной связиТелефония, телекоммуникации, офисные АТСБытовая техника
Программы
Игры
Авторские форумы
Прочие форумы
Архивы конференции
Архив "О Конференции"Архив "Процессоры"Архив "Разгон и охлаждение"Архив "Системные платы"Архив "Модули памяти"Архив "Видеосистема"Архив "Видеозахват"Архив "Мониторы и другие устройства отображения"Архив "Цифровое изображение"Архив "Цифровой звук"Архив "Периферия"Архив "Корпуса, блоки питания, UPS"Архив "Коммуникации: сети и сетевые технологии"Домашний интернет, модемы (архив)Архив "Системное администрирование, безопасность"Архив "Мобильная связь"Программы Microsoft: Windows, Office, Server, Windows LiveАрхив "OС и системное ПО"Архив "Программы: Интернет"Архив "Программирование"Форум прикладных программистовАрхив "Электронные устройства и компоненты"Архив "Околокомпьютерный Флейм & Общий"Архив "Полемика (Злобный Флейм)"Околоавтомобильный ФлеймФорум ремонтниковВопросы компании IntelФотокамеры SamsungФорум о магазине приложений RuStoreФорум по продукции компании Huawei
Справка и сервисы
Другие проекты iXBT.com
sikee8: Вопрос по сокетам в Java. Почему не приходят данные пока не вызову close
sikee8
Member
Автор темы
469/774 ответов
23 года на iXBT, с января 2002
Чаще пишет в "Программирование" (26%)
Инфо Ответить
s
sikee8 MemberАвтор темы
18 лет назад / 09 декабря 2006 21:40
В общем сижу я и жду данные:

01final ServerSocket service = new ServerSocket(0);
02final int portNumber = service.getLocalPort();
03service.setSoTimeout(10000);
04Socket serviceSocket = service.accept();
05BufferedReader input = new BufferedReader(new InputStreamReader(serviceSocket.getInputStream()));
06while (true) {
07    String kkk = input.readLine();
08    if (kkk.length() > 0) {
09        System.out.println(kkk);
10        assertNotNull(kkk, null);
11        break;
12    }
13}
а в другом треде эти данные отсылаю, вот так:

01new Thread() {
02    public void run() {
03        try {
04            Socket client = new Socket("localhost", portNumber);
05            DataOutputStream out = new DataOutputStream(client.getOutputStream());
06  
07            ByteArrayOutputStream baos =  new ByteArrayOutputStream();
08            DataOutputStream dos = new DataOutputStream(baos);
09            dos.writeUTF("URAAAAAA!!!!!!!!");
10            dos.close();
11            byte[] packet = baos.toByteArray();
12            out.write(packet);
13            out.flush();
14//          out.close();
15  
16        } catch (IOException e) {
17            e.printStackTrace();
18        }
19    }              
20}.start();
И ничего не работает, а вот если out.close() раскомментировать, то всё работает.
Почему так?
Зачем мне вызывать out.close() чтобы данные дошли? разве flush недостаточно?

Исправлено: sikee8, 09.12.2006 22:00

Maxim Karvonen
unregistered
Ответить
M
Maxim Karvonen unregistered
18 лет назад / 09 декабря 2006 22:36
Зачем мне вызывать out.close() чтобы данные дошли? разве flush недостаточно?
flush вполне достаточно для того, чтобы данные дошли и прочитались из InputStream (Socket.getInputStream()). Но у Вас вокруг InputStream обернут еще и BufferedReader, который при чтении строки делает следующее:
Read a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed.
Ну а так как в записанных данных не встречается переводов строки, BufferedReader спокойно ожидает чтения следующего символа (или конца потока данных).
DataOutputStream вокруг client.getOutputStream() в данном примере лишний, можно было сразу в client.getOutputStream() писать packet. Кстати, Вы уверены, что строку нужно выводить через DataOutputStream.writeUTF а читать с помощью BufferedReader.readLine()? Или пара лишних символов в начале строки Вам нужна?
И по коду сервера - а может assertNotNull должен стоять до if(kkk.length()>0)...? А то в случае kkk==null до assert'а дело не дойдет.
Кстати, с темой не угадали, вопрос то про BufferedReader
sikee8
Member
Автор темы
470/775 ответов
23 года на iXBT, с января 2002
Чаще пишет в "Программирование" (26%)
Инфо Ответить
s
sikee8 MemberАвтор темы
18 лет назад / 11 декабря 2006 13:51
Maxim Karvonen

спасибо за такой подробный ответ! теперь я всё понял
BufferedReader это я уже написал, вообще сначала хотел делать DataInputStream.readLine, но оказалось deprecated зато любезно предоставили строчку для копипейста с буфередридером, ну я собственно и копипейстнул

Кстати, Вы уверены, что строку нужно выводить через DataOutputStream.writeUTF а читать с помощью BufferedReader.readLine()? Или пара лишних символов в начале строки Вам нужна?
Нет, конечно так не должно быть, просто пока хотелось проверить что что-то работает, не особо задумываясь о мелочах Та часть кода которая совсем срашная не мной написано
а может assertNotNull должен стоять до if(kkk.length()>0)...? А то в случае kkk==null до assert'а дело не дойдет.
да нет ассерт стоит там где нужно, хотелось просто чтобы тест обломался а сообщение об ошибке я юзаю как дебагинформайшн вот break там не к чему конечно

Добавление от 11.12.2006 15:06:

ещё один вопрос.
в общем я стал использовать DataInputStream.readFully, но он

This method blocks until one of the following conditions occurs:
* b.length bytes of input data are available, in which case a normal return is made.

А как бы мне так проще всего сделать чтобы если например в течении нескольких секунд не прочиталось, то чтобы он вывалился, с возможностью задиагностировать что вывалился именно по таймауту?
Hedin
Member
33/775 ответов, #13 в рейтинге
19 лет на iXBT, с декабря 2005
169 фото на iXBT.photo
Чаще пишет в "Политика" (36%)
Россия, Питер
Инфо Ответить
H
Hedin Member
18 лет назад / 11 декабря 2006 19:41
sikee8
А как бы мне так проще всего сделать чтобы если например в течении нескольких секунд не прочиталось, то чтобы он вывалился, с возможностью задиагностировать что вывалился именно по таймауту?

Смотри метод Socket.setSoTimeout().
Skip
Member
839/3327 ответов
25 лет на iXBT, с января 2000
8 фото на iXBT.photo
Чаще пишет в "Программирование" (22%)
Россия, Долгопрудный
Web-страница
Инфо Ответить
S
Skip Member
18 лет назад / 11 декабря 2006 22:55
sikee8:
в общем я стал использовать DataInputStream.readFully, ...
С ним есть одна проблема. Вы не можете ручаться, что Вам действительно придет весь объем данных, который может вместить массив. И тогда либо по таймауту вываливаться, что не есть хорошо, либо висеть.

Проще читать просто массивом, анализируя, сколько считано. Во-первых, не блокируется. Во-вторых, всегда можно понять, что поток кончился - read вернет -1.
sikee8
Member
Автор темы
471/778 ответов
23 года на iXBT, с января 2002
Чаще пишет в "Программирование" (26%)
Инфо Ответить
s
sikee8 MemberАвтор темы
18 лет назад / 13 декабря 2006 17:43
Hedin

спасибо, помогло

Skip

Моя задача была проверить что что-то пришло. В моей ситуации это самое большее что я могу сделать, поскольку метод не специфицирует формат сообщения. Поэтому я объявил byte[1] и передал его в readFully, если хотя бы один байт дошёл - ура. Если нет вываливаемся по таймауту в SocketTimeoutException и там говорим fail.
sikee8
Member
Автор темы
498/813 ответов
23 года на iXBT, с января 2002
Чаще пишет в "Программирование" (26%)
Инфо Ответить
s
sikee8 MemberАвтор темы
18 лет назад / 17 января 2007 22:05
Ещё одну странность нашёл

Конструктор ServerSocket переводит в LISTENING state, если ему указать порт.
Вот смотрите, запустил вот такую программу:
1import java.net.Socket;
2import java.net.ServerSocket;
3  
4public class TestSocket {
5  public static void main(String[] args) throws Exception {
6    ServerSocket service = new ServerSocket(23459);
7    Thread.sleep(100000)
8  }
9}

а потом сделал вот так:

netstat -na | grep 23459
*.23459 *.* 0 0 49152 0 LISTEN
~;

Вопрос, ЗАЧЕМ нужен метод accept? Ведь это он:

Listens for a connection to be made to this socket and accepts it.

Тогда я решил проверить, а можно ли отсылать данные на сокет на который не было сделано accept?
01import java.net.Socket;
02import java.net.ServerSocket;
03  
04import java.io.DataInputStream;
05import java.io.OutputStream;
06  
07import java.util.Arrays;
08  
09public class TestSocket {
10  public static void main(String[] args) throws Exception {
11    ServerSocket service = new ServerSocket(23490);
12  
13    Socket socket = new Socket("localhost", 23490);
14    byte[] data = {'h', 'e', 'l', 'l', 'o'};
15    OutputStream os = socket.getOutputStream();
16    os.write(data);
17    os.flush();
18  
19    Socket serviceSocket = service.accept();
20    DataInputStream in = new DataInputStream(serviceSocket.getInputStream());
21    byte[] receive = new byte[5];
22    in.readFully(receive);
23    System.out.println(Arrays.toString(receive));
24  }
25}

И оказывается можно. Их можно не только отсылать, можно ещё и получать. Вот он, аутпут:

1java TestSocket
2[104, 101, 108, 108, 111]

Вот лично для меня несколько странно что сокет сразу весит в listening state, тогда как это, на мой взгляд, должен делать accept. Почему так всё странно?
Венгерович Михаил
unregistered
Ответить
В
Венгерович Михаил unregistered
18 лет назад / 18 января 2007 17:35
sikee8
Почему так всё странно?
Все не странно, а так и задумано. Если указываешь [адрес, очередь, ] порт при создании сокета, он автоматом биндится.
Сделано это для тех сокетов, которые нельзя создать в незабинженом состоянии. Т.е. при попытке согдать его (такой сокет) без параметров получишь эксепшен. Например так поступают некоторые реализации SSL.
sikee8
Member
Автор темы
499/814 ответов
23 года на iXBT, с января 2002
Чаще пишет в "Программирование" (26%)
Инфо Ответить
s
sikee8 MemberАвтор темы
18 лет назад / 18 января 2007 17:43
Венгерович Михаил

Как всё странно
Тогда уж в описании функции accept:
Listens for a connection to be made to this socket and accepts it.
нужно добавить
Listens (if not already listening) for a connection to be made to this socket and accepts it.
А то как-то путанно получается...
Alexander Gurov
Member
124/561 ответов
21 год на iXBT, с июля 2003
Чаще пишет в "Наука" (41%)
Украина, Kharkov
Инфо Ответить
A
Alexander Gurov Member
18 лет назад / 18 января 2007 22:54
sikee8
Вообще LISTEN сокет на более низком уровне это сокет проверяемый на чтение (собственно, да, Вы можете туда писать ). Внешнее воздействие приводит к постановке в очередь запроса на соединение. Для большинства систем по умолчанию размер очереди равен 5 запросам. Реальное соединение устанавливается во время исполнения функции accept(). CONNECT сокет при этом (при установлении соединения) переходит в состояние "доступен на запись". А LISTEN сокет так и остается "слушать", то есть через один слушающий сокет Вы можете установить множество соединений.
sikee8
Member
Автор темы
500/815 ответов
23 года на iXBT, с января 2002
Чаще пишет в "Программирование" (26%)
Инфо Ответить
s
sikee8 MemberАвтор темы
18 лет назад / 19 января 2007 02:56
Alexander Gurov
Вообще LISTEN сокет на более низком уровне это сокет проверяемый на чтение (собственно, да, Вы можете туда писать ).

вот этого я и не понимаю, КАК я могу писать в сокет, который НЕ НАХОДИТЬСЯ в состоянии CONNECT
Насколько я помню, у нас тройное рукопожатие идёт (кажеться)
Ну в общем суть в том что сначала
1. Сокет вешается в LISTENING
2. С удалённого хоста идёт запрос на конект
3. Отсылается подтверждение коннекта, при этом по идее должен сообщиться номер TCP пакета(вообще там два номера вроде, SYN и ACK, один в одну сторону, другой в другую)

Кароче суть в том что написать в сокет который просто находиться в LISTENING state, невозможно, просто потому что нету необходимых для TCP соединения чисел (SYN и ACK).

Вообще я так думаю что тут другой артефакт произошёл, все эти данные закэшировались, а реально отправились только после acceptа.

В общем для меня странно одно, то что ServerSocket вещается в listening state без вызова accept - кому и зачем понадобилась такая функциональность - для меня загадка. Надо мне создать сокет - я создам. Надо повесить в listening - я вызову accept.
А так получается создал ServerSocket, он повис в листенинг, туда народ будет конектиться, а я например accept так ни разу и не вызову. И что получаеться? Получается что зря конектились. У них заведома не было ни одного шанса. Но зачем тогда переводить сокет в LISTENING? Непонятно. А мне вот довольно сложно по назначению использовать непонятное API, а приходиться.
CrazyElk
unregistered
Ответить
C
CrazyElk unregistered
18 лет назад / 19 января 2007 10:29
ServerSocket service = new ServerSocket(23490);
Просьба OS при зарезервировать порт 23490 за точкой доступа описываемой возвращаемым сокетом (service). Указаний о том что делать с пакетами поступающими в адрес этого порта нет. С другой стороны с этого момента порт связан с сервисом (серверным сокетом) и когда то позже от него поступят указания что с ними делать . Поэтому OS принимает все запросы на соединения с сервисом а пакеты поступающие по ним откладываются в буфер приема и будут обработаны сервисом позже когда он сможет. Если бы порт не был зарезервирован то пакеты обрабатывала сама OS отказывая в соединении NAC и посылая запрос разрыва соединения при поступлении данных по соединению о существовании которого она не знает. А так ответственность за то что делать с данными зарезервировало за собой приложение создавшее серверный сокет - OS стоит в сторонке и просто буферизует данные для приложения (не до бесконечности само собой)
...
Socket serviceSocket = service.accept();
Приложение сигнализирует OS о том что оно свои дела сделало и готово заняться очередным соединением (и его данными) которые для него OS для него подготовило. Несмотря на то что клиенты коннектелись в произвольные времена в том числе и в те моменты когда серверная нить исполнения принять заняться соединением не могла - соединение было принято и сервер имеет возможность его данные обработать.

Ну а теперь представим на секундочку что API вдруг сделали "логичным" как Вы предлагаете - то есть все запросы установления соединения вне времени ожидания в вызове service.accept() идут лесом - домашнее задание подумать что будет с двумя последовательными вызовами идущими с разных хостов поступившими практически одновременно. Правильно один из них пришедший в момент когда серверная нить исполнения вышла service.accept() и занимается первым запросом идет лесом без объяснения причин. На гневный вопрос клиента "а почему собственно, а какого?" сервис удивленно говорит "а был мальчик? собственно!" мне о вашей попытке со мной связаться ничего неизвестно - Ну правильно в таком API ее отвергли даже не уведомляя сервер. По причине что именно в эту миллисекуду когда поступил запрос, серверу его не ждал и другими делами занят. А эти другие дела после выхода из service.accept() ой какие не быстрые могут быть. Пусть эти другие дела занимают 1 секунду (кошмарно большое время для принимающего соединение кода). Тогда сервис способен обработать 60 запросов в минуту НО если они поступают не чаще чем раз в секунду - Бред посчитай сам эффективную скорость обработки при случайном равномерном распределении запросов клиентов по времени с средней частотой 60 запросов в секунду. Независимые клиенты в сети синхронизовать свои запросы не имеют ни каких шансов и прогнут сеть своей настойчивой долбежкой к северу который постоянно их посылает. Нет уж пусть будет такой как сейчас - создал серверный сокет значить объявил о существовании сервиса на порту XXXX к которому можно посылать запросы. И пока средняя частота запросов на соединение не превышает возможностей сервера для их приема клиенты могут обращаться в произвольном порядке и с произвольной частотой OS обеспечит буферизацию и выравнивание загрузки по времени.

Счастья всем и пусть никто (и клиентов) не уйдет обиженным. Если возможности сервера по полноценной обработке запроса будут исчерпываться - нормально написанный сервер просто закрывает невозможные к обработке соединения (осознанно а не потому что случайно в момент поступления запроса другим был занят – то есть по факту обрабатывает все соединения - часть нормально, часть "варварским" способом. И это логично - взялся работать сервисом работай. А если ни разу accept() не вызвать OS сама закрое все принятые соединения по этому порту – по факту "варварски" обработав запросы клиентов. Но по любому это решение обработать нормально или послать принималось сервером толи тем что он сам закрывал принятый сокет, толи тем что приказал закрыть все принятые закрыв серверный. Но никакой отсебятины OS пока сервис был определен на порту не несла.

WBR CrazyElk
sikee8
Member
Автор темы
501/816 ответов
23 года на iXBT, с января 2002
Чаще пишет в "Программирование" (26%)
Инфо Ответить
s
sikee8 MemberАвтор темы
18 лет назад / 19 января 2007 14:00
CrazyElk

спасибо большое за объяснение, теперь осознал
насколько я понял если я делаю new ServerSocket, потом жду скажем минутку, за эту минуту ко мне приходят скажем пять запросов на коннект. Если после этого я сделаю пять раз srevice.accept(), то все пять acceptов вернут сокет немедленно. И это будут те 5 сокетов которые уже давно находятся в состоянии connect.
Если так то теперь мне совсем до конца всё стало ясно
Harkonnen
Member
3878/11134 ответов
25 лет на iXBT, с февраля 2000
Чаще пишет в "Наука" (45%)
Инфо Ответить
H
Harkonnen Member
18 лет назад / 20 января 2007 06:34
sikee8
Если только те клиенты по собственным тайм-аутам не отвалятся за эту минутку

Когда пишешь код, иногда полезно прикинуть, что у тебя "зависон" (e.g. дикий своп) секунд на 10 между каждымим подряд идущими строчками (а по сути - между каждой парой asm инструкций на уровне железа). При чём то 8, то 12 - т.е. непредсказуемые такие паузы Тогда все синхронизационные заморочки - как на ладони (особенно с потоками подобное "мышление" помогает). А OS этих зависонов лишена потому что она реагирует на поступающие коннекты в kernel mode - т.е. процессор "мгновенно" прерывается по прибитию пакета на сетевую карту (на уровне IRQ линий железа, никаких периодических опросов) и пакет "немедленно" же обрабатывается ("немедленно" - зависит только от скорости процессора). User mode код (твой код) лишён этой првелегии - поэтому кушает то время, которое есть. Хоть по такту в час. Т.е. "подряд идущие" команды на уровне Java, C++, etc... могут оказаться далеко не подряд идущими относительно всего чем занят процессор. Да - относительно друг-друга они всё еще будут подряд идущими. Но только относительно друг-друга. А в реале это может минутами оказаться. Я это всё к тому, что твоё "заблуждение", вероятно, спровоцировано мысью о "моментальном" исполнении цикла с accept'ом. Это не так.
Ваш ответ:

Нет значка Нет значка Вот тут! Лампочка Восклицание Вопрос Класс! Улыбка Злость Огорчение Поговорим? Краснею Подмигивание Ругаю ОдобряюBIUdelSxsupxsuboffsp spoilerqurlimgvideo• list1. list1 codeprecenter-hr-rusQWE→ЙЦУ
файлыочистить
Ваше имя: Авторизуйтесь Предпросмотр В полную форму
вставить выделенную цитату в окно ответа
Если Вы считаете это сообщение ценным для дискуссии (не обязательно с ним соглашаться), Вы можете поблагодарить его автора, а также перечислить ему на счет некоторую сумму со своего баланса (при отзыве благодарности перечисленная сумма не будет вам возвращена).
Также вы можете оценить сообщение как неудачное.
В течение суток можно 20 раз оценить сообщения разных участников (купите Premium-аккаунт, либо оплачивайте оценки сверх лимита).
Если Вы считаете это сообщение ценным для дискуссии (не обязательно с ним соглашаться), Вы можете поблагодарить его автора, а также перечислить ему на счет некоторую сумму со своего баланса (при отзыве благодарности перечисленная сумма не будет вам возвращена).
Также вы можете оценить сообщение как неудачное.
В течение суток можно 20 раз оценить сообщения разных участников (купите Premium-аккаунт, либо оплачивайте оценки сверх лимита).