Klient - serwer przesylanie bajtow

0

Ok, sprawa wyglada tak. Wiekszosc Javowych strumieni wspiera stringi i ma metody w stylu readLine(). W moim projekcie komunikacja odbywa sie poprzez wysylanie tablic bajtow. Teraz moje pytanie sklania sie do tego, w jaki sposob mozna odebrac cala tablice za jednym razem? Tzn, chce zeby watek sie blokowal w momencie gdy strumien wejsciowy jest pusty, w momencie przesylania tablicy sie odblokowywal i pobieral ja cala. Moglem to slabo sprecyzowac, ale jesli ktos sie zainteresuje tym problemem chetnie odpowiem na jakiekolwiek pytania.

0

Moze w kwestii wyjasnienia, na ta chwile watek serwera ma taki blok;
.
.
DataInputStream in = new DataInputStream(socket.getInputStream());
ByteArrayOutputStream bout = new ByteArrayOutputStream();
.
.
.
byte bajt;
do{
bajt=in.readByte();
bout.write(bajt);
}while(in.available()>0);

Tylko o ile to dziala, to zastanawiam sie co by bylo gdyby klient wyslal 2 wiadomosci niemal rownoczesnie, w sensie ze serwer nie zdazyl by przetworzyc tej i juz odbieral nowa. Wydaje mi sie, ze wowczas by sie wszystko posypalo. Problem jest taki, ze przesylane dane sa szyfrowana, wiec nie mam zadnego wzgledu w to, w jaki sposob wygladal bedzie ost bajt danej tablicy.

0

Calkowicie zle - avaialble() moze zwrocic zero jesli w danej chwili nie ma bajtow, ale za sekunde moga byc, a petla juz przerwana. Do tego sluzy metoda read() i porownywanie do -1 (EOF) lub (lepiej) metoda read(byte[]) i porownywanie zwroconej wartosci do -1 (liczba wczytanych bajtow). Cos w stylu:
ByteArrayOutputStream bout = ...
byte[] buffer = new byte[4096];
int read;
while ((read = in.read(buffer)) != -1) {
bout.write(buffer, 0, read);
}
// gdy znajdzie sie tutaj, znaczy ze wszystko wczytane

0
::. napisał(a)

Calkowicie zle - avaialble() moze zwrocic zero jesli w danej chwili nie ma bajtow, ale za sekunde moga byc, a petla juz przerwana. Do tego sluzy metoda read() i porownywanie do -1 (EOF) lub (lepiej) metoda read(byte[]) i porownywanie zwroconej wartosci do -1 (liczba wczytanych bajtow). Cos w stylu:
ByteArrayOutputStream bout = ...
byte[] buffer = new byte[4096];
int read;
while ((read = in.read(buffer)) != -1) {
bout.write(buffer, 0, read);
}
// gdy znajdzie sie tutaj, znaczy ze wszystko wczytane

Zeby takie cos dzialalo, musialbym po wyslaniu tablicy bajtow wywolac metode close() dla strumienia wyjsciowego. Pytanie tylko po co mam zamykac strumien? No chyba ze czegos nie rozumiem.

0

Jeśli długość tablicy nie jest statyczna, zawsze przed wysłaniem podaj najpierw jej długość w jednym lub dwóch bajtach.

// jesli dlugosc nie jest statyczna
int left = (in.read() << 8) | in.read();
byte[] buff = new byte[left];


while(left>0)
{
    int readen = in.read(buff, buff.length-left, left);
    if(readen < 0)
    {
       // pasowaloby rzucic wyjatek
    }
    left-=readen;
}

(pisane z palca na forum, mogłem coś je..ąć)

0

To jest sposob, aczkolwiek myslalem ze mozna zrobic to w jakis latwiejszy sposob. A nie da sie bez zamykania strumienia w sposob javny wyslac sygnalizacje o zakonczeniu? Swoja droga metoda ktora napisalem dziala, wiec kwestia jest taka, kiedy to sie wysypie?

0

Jesli nie chcesz zamykac to powyzej opisany sposb jest dobry.
To ze teraz dziala to przypadek - to ze zapiszesz tablice o wielkosci xxx do strumienia nie znaczy ze te xxx bedzie od razy dostepne po drugiej stronie - wiecej, poszukaj sobie na forum, bylo cos podobnego, zobaczysz ze jest wielec pradwopodobne ze nie bedzie od razu dostepne. Zeby w sposob stabilny i zawsze poprawny wczytac tablice zawsze musisz to robic w takiej petli.
Jelsi chcesz latwiejszy sposob to serializacja - Object streamy sie martwia za Ciebie co i ile odebrac. Jednakze tam sa inne problemy...

0
::. napisał(a)

Jesli nie chcesz zamykac to powyzej opisany sposb jest dobry.
To ze teraz dziala to przypadek - to ze zapiszesz tablice o wielkosci xxx do strumienia nie znaczy ze te xxx bedzie od razy dostepne po drugiej stronie - wiecej, poszukaj sobie na forum, bylo cos podobnego, zobaczysz ze jest wielec pradwopodobne ze nie bedzie od razu dostepne. Zeby w sposob stabilny i zawsze poprawny wczytac tablice zawsze musisz to robic w takiej petli.
Jelsi chcesz latwiejszy sposob to serializacja - Object streamy sie martwia za Ciebie co i ile odebrac. Jednakze tam sa inne problemy...
Niby tak, ale powyzej opisany sposob wprowadza zbyt duze opoznienia dla mojego projektu. Tzn, kwestia jest taka ze jak chyba wspomnialem, dane sa szyfrowane. Oznacza to, ze zawsze jest jakies dopelnienie, a wiec bez wiekszych wyjasnien powiem ze te 2 bajty skutkowalyby 16 bajtowym nadmiarem (dopelnienie dla AESa). Zeby juz byc calkiem doslownym, ta tablica to stalej dlugosci naglowek, plus pakiet danych. Wiec moglbym rozmiar dodac w naglowku, co glupie nie jest, ale stopowalo by wczytywanie danych do momentu az naglowek nie zostanie przetworzony (tu rozszyfrowany). Dlatego tez mialem nadzieje ze da sie w jakis jawny sposob bez zamykania strumienia przekazac znak zakonczenia. Nie sadze, tez zeby przesylanie danych jako obiekty mi w jakikolwiek sposob pomoglo. Z tym available() sie zgodze, tez tak uwazam. Po prostu poki co mi dziala. W momencie gdyby przetwarzanie danych zajmowalo duzo czasu, mogloby dojsc do sytuacji ze dwie wiadomosci sie zleja w jedna calosc. Mimo wszystko wydaje mi sie to troche nierozsadne, ze nie ma nic wbudowanego w Jave co by mi w danej sytuacji pomoglo.

0
iluminacja napisał(a)

Mimo wszystko wydaje mi sie to troche nierozsadne, ze nie ma nic wbudowanego w Jave co by mi w danej sytuacji pomoglo.
A co miałoby być? Komunikujesz się przez tcp/ip, więc Java nie ma tutaj nic do rzeczy.

Skoro długość nagłówka jest statyczna, to jak pisałem, nie wysyłasz i nie czytasz jej, robisz jak podałem powyżej, z tym, że zamiast czytania długości po prostu robisz

int left = STATYCZNA_GLUGOSC;

btw:

iluminacja napisał(a)

opisany sposob wprowadza zbyt duze opoznienia dla mojego projektu. Tzn, kwestia jest taka ze jak chyba wspomnialem, dane sa szyfrowane.
Nie wiem czym Ty to szyfrujesz, bo zwykle szybkość szyfrowania i tak jest dużo większa niż szybkość przesyłu danych. Zatem spowolnienie spowodowane szyfrowaniem nie powinno być nawet zauważalne...

0
Keraj napisał(a)
iluminacja napisał(a)

Mimo wszystko wydaje mi sie to troche nierozsadne, ze nie ma nic wbudowanego w Jave co by mi w danej sytuacji pomoglo.
A co miałoby być? Komunikujesz się przez tcp/ip, więc Java nie ma tutaj nic do rzeczy.

Skoro długość nagłówka jest statyczna, to jak pisałem, nie wysyłasz i nie czytasz jej, robisz jak podałem powyżej, z tym, że zamiast czytania długości po prostu robisz

int left = STATYCZNA_GLUGOSC;

Wiem jak to zrobic. Po prostu mialem nadzieje, ze mozna to zrobic latwiej :)

btw:

iluminacja napisał(a)

opisany sposob wprowadza zbyt duze opoznienia dla mojego projektu. Tzn, kwestia jest taka ze jak chyba wspomnialem, dane sa szyfrowane.
Nie wiem czym Ty to szyfrujesz, bo zwykle szybkość szyfrowania i tak jest dużo większa niż szybkość przesyłu danych. Zatem spowolnienie spowodowane szyfrowaniem nie powinno być nawet zauważalne...
Opoznienie wiaze sie z koniecznoscia odebrania calego naglowka, a nastepnie go przetworzenia, gdzyz sprawdzana jest takze integralnosc danych funkcja MAC. Szyfruje AESem, w trybie CBC. Nie jest to szyfr strumieniowy, aczkolwiek opoznienie i tak bedzie znikome.

1 użytkowników online, w tym zalogowanych: 0, gości: 1