powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Оптимизация?
18 сообщений из 18, страница 1 из 1
Оптимизация?
    #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
Оптимизация?
    #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
Оптимизация?
    #38493667
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GorloPavel,

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

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

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

А там и сеть мои пакеты! 4 байта заголовок.
...
Рейтинг: 0 / 0
Оптимизация?
    #38493773
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Как еще проще сделать? Сейчас пакеты такие: 4 байта заголовок(размер полезных данных), остальное полезные данные.
...
Рейтинг: 0 / 0
Оптимизация?
    #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
Оптимизация?
    #38494379
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пакет вида "длина данных, данные" - не очень хорошее решение, т.к. вы не можете начинать отправку, не узнав размер отправляемых данных.
Начнёте делать конвейер - или вас проклянут или сами себя проклянёте.
...
Рейтинг: 0 / 0
Оптимизация?
    #38494923
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. SidorovПакет вида "длина данных, данные" - не очень хорошее решение, т.к. вы не можете начинать отправку, не узнав размер отправляемых данных.
Начнёте делать конвейер - или вас проклянут или сами себя проклянёте.
Предложите решение лучше и что-бы не было недостатков описанных в первом посте.
...
Рейтинг: 0 / 0
Оптимизация?
    #38495009
maxkar
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GorloPavelДа это вообще решается еще проще :) Вы просто не поняли вопроса.
А, я вернуть res из метода забыл. Это вместо всего вашего кода с парой буферов и копированием данных (и еще оберкти по чтению/перекладыванию данных). Т.е. сначала читаем длину (readBytes(is, 4)), затем парсим длину и читаем данные (readBytes(is, totalBytes)). А затем байты передаем обработчику. В любом случае от парсинга вы не избавитесь. Но в pull-варианте (читать блоки нужных размеров) он гораздо проще для чтения/реализации, чем в push-варианте (когда данные в парсер кормятся извне по частям).
...
Рейтинг: 0 / 0
Оптимизация?
    #38495639
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
maxkarGorloPavelДа это вообще решается еще проще :) Вы просто не поняли вопроса.
А, я вернуть res из метода забыл. Это вместо всего вашего кода с парой буферов и копированием данных (и еще оберкти по чтению/перекладыванию данных). Т.е. сначала читаем длину (readBytes(is, 4)), затем парсим длину и читаем данные (readBytes(is, totalBytes)). А затем байты передаем обработчику. В любом случае от парсинга вы не избавитесь. Но в pull-варианте (читать блоки нужных размеров) он гораздо проще для чтения/реализации, чем в push-варианте (когда данные в парсер кормятся извне по частям).
Не понял как ваш код может помочь в ситуации описаной выше. Вы ведь просто читаете данные из стрима и все!
...
Рейтинг: 0 / 0
Оптимизация?
    #38495871
am_sasa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
GorloPavel,

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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



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


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