TCP Socket

VO
  • Rejestracja:ponad 5 lat
  • Ostatnio:ponad 4 lata
  • Postów:43
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):

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

ODBIÓR (odczytuje po jednym bajcie):

Kopiuj
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++;
            }
W0
  • Rejestracja:ponad 12 lat
  • Ostatnio:około godziny
  • Postów:3594
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:

Kopiuj
int sizeOfData = sizeBuffer.getInt();

Zgodnie z https://docs.oracle.com/javase/7/docs/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
VO
  • Rejestracja:ponad 5 lat
  • Ostatnio:ponad 4 lata
  • Postów:43
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:

Kopiuj
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):

Kopiuj
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
Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:prawie 2 lata
  • Lokalizacja:Wrocław
  • Postów:13042
2

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:

Kopiuj
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
VO
  • Rejestracja:ponad 5 lat
  • Ostatnio:ponad 4 lata
  • Postów:43
0

Ok spróbuje :)

edytowany 1x, ostatnio: volau
VO
  • Rejestracja:ponad 5 lat
  • Ostatnio:ponad 4 lata
  • Postów:43
0

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

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.