TCP Socket

Odpowiedz Nowy wątek
2019-10-28 19:42

Rejestracja: 7 miesięcy temu

Ostatnio: 19 minut temu

0

Mam dziwny problem wysyłam dane po tcp/ip ale odbiorca otrzymuje więcej niż wysłałem. Czy tcp/ip coś dokleja do danych? (wysyłam tylko jedna paczkę byte'ów).
Wysyłka to zwykły Socket, natomiast odbiór jest AsynchronousSocketChannel.

Wysyłanie (pierw wysyłam rozmiar jako int, potem po zatwierdzeniu przez klienta wysyłam dane jak niżej):

public void send(byte[] data) {
        try {
            outputStream.write(data);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

ODBIÓR (odczytuje po jednym bajcie):

ByteBuffer sizeBuffer = ByteBuffer.allocate(Integer.BYTES);
            clientConnection.read(sizeBuffer).get(15, TimeUnit.SECONDS);
            sizeBuffer.flip();
            int sizeOfData = sizeBuffer.getInt();
            sizeBuffer.clear();

            sendConfirmation();

            ByteBuffer dataBuffer = ByteBuffer.allocate(sizeOfData);
            int byteCounter = 0;
            while (byteCounter < sizeOfData) {
                ByteBuffer temporaryDataBuffer = ByteBuffer.allocate(1);
                clientConnection.read(temporaryDataBuffer).get(15, TimeUnit.SECONDS);
                temporaryDataBuffer.flip();
                dataBuffer.put(temporaryDataBuffer.array());
                byteCounter++;
            }

Pozostało 580 znaków

2019-10-29 11:42

Rejestracja: 7 lat temu

Ostatnio: 12 godzin temu

0

Korzystając z protokołu traktujesz protokół jako taką firmę transportową. Firma wyśle to, co nadasz. I odbierze to, co zechcesz odebrać. Wszelkie dodatkowe rzeczy, które wysyła TCP/IP są dla ciebie transparentne.

Problem jest tutaj:

int sizeOfData = sizeBuffer.getInt();

Zgodnie z https://docs.oracle.com/javas[...]/api/java/nio/ByteBuffer.html ByteBuffer.getInt() wczytuje jakiegoś int'a z buforu, który nie ma nic wspólnego z rozmiarem.

edytowany 1x, ostatnio: wartek01, 2019-10-29 11:42

Pozostało 580 znaków

2019-11-01 13:24

Rejestracja: 7 miesięcy temu

Ostatnio: 19 minut temu

0

Tutaj jest dobrze bo robię putInt wysyłam i server prawidłowo odbiera wielkość, potem według tej wielkości robi odbiór po jednym bajcie aż zbierze całość i tutaj tez jest dobrze.
Server dokleja moj separator w postaci ciagu bajtow:

byte[] SEPARATOR = {1,1,2,2,1,1,1,1};

Dodaje taki separator na poczatku i koncu czyli: SEPARATOR + dane + SEPARATOR
wysyla calosc do zasubskrybowanych odbiorcow.

Problem pojawia się po stronie clienta bo robię odbiór nie po jednym bajcie a po 1024 (żeby było szybciej) i tutaj zaczyna się problem bo dane w 90% przypadkach odbieram jakieś nadmiarowe.
Funkcja dzieląca według separatora działa prawidłowo ale coś mi dokleja jakieś nadmiarowe dane.
Jak zbieram po jednym bajcie to wszystko działa jak powinno problem jest gdy zbieram po 1024.
Server wysyła całość z separatorem np: 4500 bajtów a client odbiera 6500. Widać w tablicy separatory i w danych wysłanych jakieś doklejone bajty których nie wysyłałem.

Odbiór przez clienta (logika przed refaktorem):

private byte[] read() {
        List<Byte> receivedByteArray = new ArrayList<>();

        try {
            byte[] buffer = new byte[1024]; // jak ustawie na 1 to działa dobrze
            while (inputStream.read(buffer) > 0) {
                for(byte b : buffer) receivedByteArray.add(b);
            }
        } catch (Exception ex) {
            if(!(ex instanceof SocketTimeoutException)) ex.printStackTrace();
        }

        byte[] receivedData = new byte[receivedByteArray.size()];
        for (int i = 0; i < receivedByteArray.size(); i++) {
            receivedData[i] = receivedByteArray.get(i);
        }

        return receivedData;
    }
edytowany 2x, ostatnio: volau, 2019-11-01 13:26

Pozostało 580 znaków

2019-11-01 13:31
Moderator

Rejestracja: 12 lat temu

Ostatnio: 4 minuty temu

Lokalizacja: Wrocław

Twój problem polega na tym, że ignorujesz wartość zwracaną przez inputStream.read(buffer) i za każdym razem na pałę wrzucasz wszystkie bajty do receivedByteArray - prawidłowo powinno to być coś w stylu:

byte[] buffer = new byte[1024];

while (true) {
  int readBytes = inputStream.read(buffer); // zauważ, że *ostatnia porcja danych* może zwrócić np. readBytes = 3 (a nie pełne 1024)

  if (readBytes <= 0) {
    break;
  }

  for (int i = 0; i < readBytes; i += 1) {
    receivedByteArray.add(buffer[i]);
  }
}

edytowany 3x, ostatnio: Patryk27, 2019-11-01 13:41

Pozostało 580 znaków

2019-11-01 13:35

Rejestracja: 7 miesięcy temu

Ostatnio: 19 minut temu

0

Ok spróbuje :)

edytowany 1x, ostatnio: volau, 2019-11-01 13:36

Pozostało 580 znaków

2019-11-01 16:17

Rejestracja: 7 miesięcy temu

Ostatnio: 19 minut temu

0

Faktycznie tu był problem, dzięki wielkie za pomoc! :)

Pozostało 580 znaków

Odpowiedz

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