Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Java [игнор отключен] [закрыт для гостей] / Оптимизация? / 18 сообщений из 18, страница 1 из 1
09.12.2013, 08:57:54
    #38493635
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
Здравствуйте. Существует проблема с манипуляцией полученных данных, особенно если используется протокол TCP. Дело в том, что при отправке сразу нескольких пакетов данных (максимальный размер пакета TCP 8192 байта) происходит «склеивание» пакетов. То, что TCP склеивает данные в один поток, не всегда удобно. Во многих случаях пакеты, приходящие по сети, обрабатываются отдельно, поэтому и читать их из буфера желательно тоже по одному. Это просто сделать, если все пакеты имеют одинаковую длину. Но если пакеты имеют разную длину, принимающая сторона заранее не знает, сколько байт нужно прочитать из буфера, чтобы получить ровно один пакет и ни байта больше. Чтобы обойти эту ситуацию, в пакете можно предусмотреть обязательный заголовок фиксированной длины, одно из полей которого хранит длину пакета. В этом случае принимающая сторона может читать пакет по частям: сначала заголовок известной длины, а потом и тело пакета, размер которого стал известен благодаря заголовку.
Но самым неудобным является то, что пакеты не только склеиваются, но и разбиваются на части. Принимающая сторона может получить пакет меньшего размера, чем отправленный. Это значит, что отправленный пакет был послан по частям, и на момент его чтения принимающей стороной ещё не все части были получены. В этом случае нужно повторить операцию чтения данных, пока не будет получено всё, что нужно.

Вот мое решение, но можно ли как-то проще сделать? :)

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
private final static int HEADER_SIZE = 4;

private byte[] mBuffer = null;
private byte[] mHeader = new byte[HEADER_SIZE];
private byte[] mPacket = null;
private boolean mNeedHeader=false;
private boolean mNeedPacket =false;
private int mLackBytes=0;

private void splitData(byte[] data, int receivedBytes){
		int offsetData=0;
		int packetSize=0;
		
		//Нужно восстановить заголовок
		if(mNeedHeader){
			//Если количество полученных данных достаточно для восстановления
			if(mLackBytes<=receivedBytes){
				System.arraycopy(data, 0, mBuffer, HEADER_SIZE-mLackBytes, mLackBytes);//Копируем недостающие данные
				mBuffer=new byte[toInt32(mBuffer)];//узнаем длинну пакета и создаем новый буфер равный длинне пакета
				offsetData+=mLackBytes;//смещаемся дальше
				mLackBytes=mBuffer.length;//Теперь требуемое количество равно длинне пакета
				mNeedHeader=false;//Заголовок уже не нужен
				mNeedPacket=true;//Теперь нужен пакет
			}else{
				//Восстанавливаем сколько можем
				System.arraycopy(data, 0, mBuffer, HEADER_SIZE-mLackBytes, receivedBytes);
				mLackBytes-=receivedBytes;//Уменьшаем требуемое количество
				return;//Выходим и ждем сл. итерации
			}
		}
		
		//Нужен пакет?
		if(mNeedPacket){
			//Если данных достаточно, то...
			if(mLackBytes<=receivedBytes){
				System.arraycopy(data, offsetData, mBuffer, mBuffer.length-mLackBytes, mLackBytes);//Копируем нужное количество
				offsetData+=mLackBytes;//смещаемся дальше
				mNeedPacket=false;//пакет восстановлен
				onPacket(mBuffer);//Вернем пакет!!!
			}else{
				System.arraycopy(data, offsetData, mBuffer, mBuffer.length-mLackBytes, receivedBytes-offsetData);//Восстанавливаем сколько возможно
				mLackBytes-=receivedBytes-offsetData;//Уменьшаем требуемое количество
				return;//Выходим и ждем сл. итерации
			}
		}
		
		//Двигаемся по массиву...
		while(offsetData!=receivedBytes){
			
			//Пытаемся получить заголовок пакета(4 байта)
			if(receivedBytes-offsetData>4){

				System.arraycopy(data, offsetData, mHeader, 0, HEADER_SIZE);//Копируем 4 байта в буфер
				packetSize=toInt32(mHeader);//Узнаем длинну данных в пакете
				offsetData+=HEADER_SIZE;//Смеещние на длинну заголовка
				
				//Пытаемся извлеч тело пакета
				if(offsetData+packetSize<=receivedBytes){
					mPacket=new byte[packetSize];
					System.arraycopy(data, offsetData, mPacket, 0, packetSize);
					offsetData+=packetSize;//Смещение на длинну пакета
					onPacket(mPacket);//Вернем пакет!!!
				}else{
					//Тело пакета выходит за пределы полученых данных. Сохраним в буфер сколько возможно
					mBuffer= new byte[packetSize];
					System.arraycopy(data, offsetData, mBuffer, 0, receivedBytes-offsetData);
					mLackBytes=packetSize-(receivedBytes-offsetData);//запоминаем сколько данных не хватает для полного пакета
					offsetData+=receivedBytes-offsetData;//Смещаемся до конца
					mNeedPacket=true;//При следующей итерации получения данных нужно восстановить пакет
				}
			}else{
				//Неполный заголовок! Сохраним в буфер сколько возможно
				mBuffer=new byte[HEADER_SIZE];
				System.arraycopy(data, offsetData, mBuffer, 0, receivedBytes-offsetData);
				mLackBytes=HEADER_SIZE-(receivedBytes-offsetData);//запоминаем сколько данных не хватает для полного заголовка
				mNeedHeader=true;//При следующей итерации получения данных нужно восстановить заголовок
				offsetData+=receivedBytes-offsetData;//Смещаемся до конца
			}
		}
		
	}

...
Рейтинг: 0 / 0
09.12.2013, 09:37:49
    #38493662
maxkar
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
GorloPavelВот мое решение, но можно ли как-то проще сделать?
DataInput взять на одном конце (и использовать readFully). На другом, соответственно, DataOutput.

Вашего кода не понял. У вас там NIO что ли, что не позволяет блокироваться? Зачем такие сложности?
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
public static void readBytes(InputStream is, int bytes) throws IOException {
  final byte[] res = new byte[bytes];
  int ptr = 0;
  while (ptr < bytes) {
    final int readed = is.read(res, ptr, bytes-ptr);
    if (readed < 0)
      throw new EOFException("Missing " + (bytes-ptr) + " bytes");
    ptr += readed;
  }
}
...
Рейтинг: 0 / 0
09.12.2013, 09:45:25
    #38493667
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
GorloPavel,

Тебе уже говорили, tcp - потоковый протокол, там НЕТ пакетов.
Ты должен сам буферизировать и собирать свои пакеты.
...
Рейтинг: 0 / 0
09.12.2013, 09:52:51
    #38493675
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
И соответственно, разбиение данных на части — тоже фундаментальное свойство tcp. От него тоже нельзя избавиться никак.

И ты там что-то говорил про размер tcp пакета, такого понятия нет, не существует, tcp может передаваться пакетами низшего уровня даже разных размеров.
...
Рейтинг: 0 / 0
09.12.2013, 10:46:48
    #38493740
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
MasterZivGorloPavel,

Тебе уже говорили, tcp - потоковый протокол, там НЕТ пакетов.
Ты должен сам буферизировать и собирать свои пакеты.

А там и сеть мои пакеты! 4 байта заголовок.
...
Рейтинг: 0 / 0
09.12.2013, 11:16:59
    #38493773
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
Как еще проще сделать? Сейчас пакеты такие: 4 байта заголовок(размер полезных данных), остальное полезные данные.
...
Рейтинг: 0 / 0
09.12.2013, 11:20:29
    #38493778
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
maxkarGorloPavelВот мое решение, но можно ли как-то проще сделать?
DataInput взять на одном конце (и использовать readFully). На другом, соответственно, DataOutput.

Вашего кода не понял. У вас там NIO что ли, что не позволяет блокироваться? Зачем такие сложности?
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
public static void readBytes(InputStream is, int bytes) throws IOException {
  final byte[] res = new byte[bytes];
  int ptr = 0;
  while (ptr < bytes) {
    final int readed = is.read(res, ptr, bytes-ptr);
    if (readed < 0)
      throw new EOFException("Missing " + (bytes-ptr) + " bytes");
    ptr += readed;
  }
}


Да это вообще решается еще проще :) Вы просто не поняли вопроса.
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
public void setStream(InputStream stream) throws IOException {
	int receivedBytes;
	byte[] dataBuffer = new byte[Session.BUFFER_SIZE];

	while ((receivedBytes = stream.read(dataBuffer, 0, dataBuffer.length)) != -1) {
		splitData(dataBuffer, receivedBytes);
	}
}
...
Рейтинг: 0 / 0
09.12.2013, 17:09:24
    #38494379
Basil A. Sidorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
Пакет вида "длина данных, данные" - не очень хорошее решение, т.к. вы не можете начинать отправку, не узнав размер отправляемых данных.
Начнёте делать конвейер - или вас проклянут или сами себя проклянёте.
...
Рейтинг: 0 / 0
10.12.2013, 08:07:31
    #38494923
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
Basil A. SidorovПакет вида "длина данных, данные" - не очень хорошее решение, т.к. вы не можете начинать отправку, не узнав размер отправляемых данных.
Начнёте делать конвейер - или вас проклянут или сами себя проклянёте.
Предложите решение лучше и что-бы не было недостатков описанных в первом посте.
...
Рейтинг: 0 / 0
10.12.2013, 09:48:22
    #38495009
maxkar
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
GorloPavelДа это вообще решается еще проще :) Вы просто не поняли вопроса.
А, я вернуть res из метода забыл. Это вместо всего вашего кода с парой буферов и копированием данных (и еще оберкти по чтению/перекладыванию данных). Т.е. сначала читаем длину (readBytes(is, 4)), затем парсим длину и читаем данные (readBytes(is, totalBytes)). А затем байты передаем обработчику. В любом случае от парсинга вы не избавитесь. Но в pull-варианте (читать блоки нужных размеров) он гораздо проще для чтения/реализации, чем в push-варианте (когда данные в парсер кормятся извне по частям).
...
Рейтинг: 0 / 0
10.12.2013, 14:45:19
    #38495639
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
maxkarGorloPavelДа это вообще решается еще проще :) Вы просто не поняли вопроса.
А, я вернуть res из метода забыл. Это вместо всего вашего кода с парой буферов и копированием данных (и еще оберкти по чтению/перекладыванию данных). Т.е. сначала читаем длину (readBytes(is, 4)), затем парсим длину и читаем данные (readBytes(is, totalBytes)). А затем байты передаем обработчику. В любом случае от парсинга вы не избавитесь. Но в pull-варианте (читать блоки нужных размеров) он гораздо проще для чтения/реализации, чем в push-варианте (когда данные в парсер кормятся извне по частям).
Не понял как ваш код может помочь в ситуации описаной выше. Вы ведь просто читаете данные из стрима и все!
...
Рейтинг: 0 / 0
10.12.2013, 16:54:01
    #38495871
am_sasa
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
GorloPavel,

ну ты даешь
авторТ.е. сначала читаем длину (readBytes(is, 4))
в этом фишка, а ты по размеру буфера...
...
Рейтинг: 0 / 0
10.12.2013, 19:56:06
    #38496151
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
GorloPavelMasterZivGorloPavel,

Тебе уже говорили, tcp - потоковый протокол, там НЕТ пакетов.
Ты должен сам буферизировать и собирать свои пакеты.

А там и сеть мои пакеты! 4 байта заголовок.

Великолепно, только потоковый протокол tcp об этом не знает...
Если у тебя проблемы с реализацией на java — это понятно, но tcp тут очевидно ни при чем.

Кстати, ты можешь попробовать UDP и почувствовать разницу, как говорится...
...
Рейтинг: 0 / 0
10.12.2013, 20:00:01
    #38496154
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
GorloPavelBasil A. SidorovПакет вида "длина данных, данные" - не очень хорошее решение, т.к. вы не можете начинать отправку, не узнав размер отправляемых данных.
Начнёте делать конвейер - или вас проклянут или сами себя проклянёте.
Предложите решение лучше и что-бы не было недостатков описанных в первом посте.

Если бы я понимал, в чем твоя проблема, я бы предложил уже давно решение...
Но похоже, ты даже сам не понимаешь.

Ну, все же попытаюсь тебе объяснить....
(позже, вечером).
...
Рейтинг: 0 / 0
11.12.2013, 02:00:14
    #38496352
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
MasterZiv,

Не, уже завтра только.
...
Рейтинг: 0 / 0
11.12.2013, 16:54:36
    #38497358
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
am_sasaGorloPavel,

ну ты даешь
авторТ.е. сначала читаем длину (readBytes(is, 4))
в этом фишка, а ты по размеру буфера...

Перечитайте первый пост еще раз. Причем тут ваш код. Данные могут приходить склееными или частями...
...
Рейтинг: 0 / 0
11.12.2013, 16:59:22
    #38497372
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
MasterZivGorloPavelпропущено...

Предложите решение лучше и что-бы не было недостатков описанных в первом посте.

Если бы я понимал, в чем твоя проблема, я бы предложил уже давно решение...
Но похоже, ты даже сам не понимаешь.

Ну, все же попытаюсь тебе объяснить....
(позже, вечером).
Нет ни какой проблемы. Есть решение. Я спрашиваю можно ли сделать оптимальнее?

Проблемы такие могут быть без этого кода:
Клиент шлет севреру: "Привет друг!"
Сервер сначала получает: "Прив", потом "ет друг".

Как на сервере обрабатывать свои пакеты? Как понять что мой пакет пришел полностью и я могу что-то там делать?

псевдокод:
Код: sql
1.
2.
если "Привет!" то 
отправляем "Пока"



Вот тут кокраз и решение.
...
Рейтинг: 0 / 0
16.12.2013, 18:19:55
    #38502563
Basil A. Sidorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Оптимизация?
GorloPavelПредложите решение лучше и что-бы не было недостатков описанных в первом посте.Читать входной поток данных, пока он не закончится.
Разных вариантов форматирования сообщений - вагон и маленькая тележка: от (канонических) текстовых строк (CRLF) до MIME/XML и прочих JSON-ов.
...
Рейтинг: 0 / 0
Форумы / Java [игнор отключен] [закрыт для гостей] / Оптимизация? / 18 сообщений из 18, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]