TCP, как отправлять / получать большие пакеты в реальном времени на Java? - PullRequest
1 голос
/ 06 января 2012

У меня работает этот TCP-сервер, поскольку UDP-сервер мог принимать большие пакеты, но интернет-провайдер блокирует мои UDP-пакеты, даже если у меня есть публичные IP-адреса и статические службы.Но теперь решил изменить его на TCP, но у меня есть большой стек для замены на UDP для TCP.

Вот сервер, который работает, но он не получает сразу большой пакет, как я могу увеличитьэто неограниченный или максимальный размер и т. д.

1) Есть ли способ с этим?

public void run() 
{
    while(true) 
    {
        byte[] buf=new byte[5024]; <<< not helping!!
        int bytes_read = 0;
        try {                                
            bytes_read = sockInput.read(buf, 0, buf.length);                  
            String data = null;
            data = new String(buf, 0, bytes_read);                   
            System.out.println("[TCP]: incomeing data: " +  bytes_read + " bytes, data=" +data);
     }
 }

2) Есть ли способ с этим?

public TCPHandler(Socket sock) throws IOException 
{
    sock.setReceiveBufferSize(10*1024 +1024); //<<<<< not helping !!!
    sock.setSendBufferSize(10*1024+1024);
    this.sock = sock;
    sockInput = sock.getInputStream();
    sockOutput = sock.getOutputStream();
    this.myThread = new Thread(this);
}

Ни один не позволяет мне обрабатывать большие, так что я могу переключаться с UDP на TCP.Любые идеи !!

Ответы [ 4 ]

2 голосов
/ 06 января 2012

TCP и UDP разные.TCP - это не пакетный протокол, это потоковый протокол.Ваши данные будут доставлены в порядке и не будут повреждены, но не обязательно все будут доставлены сразу.

Что вам нужно сделать, это поставить префикс перед каждым набором «пакет» длиной.Когда вы получаете данные, сначала прочитайте значение длины, а затем продолжайте чтение фрагментов из сокета, пока у вас не будет необходимого объема данных.

1 голос
/ 06 января 2012

TCP - это поток байтов, часть которого вы можете получить, одно или несколько сообщений - одно чтение. При использовании пакетов UDP размером более 532 байтов пакет может быть разбит, поэтому у вас есть та же потенциальная проблема.

Простой способ кодирования сообщения - сначала отправить длину.

 final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
 final DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));

 public void writeMessage(String text) {
    out.writeUTF(text);
 }

 public String readMessage() {
    return in.readUTF();
 }

UTF для чтения / записи отправляет сначала длину, а затем содержимое

1 голос
/ 06 января 2012

Проблема в том, как работает InputStreams.Когда вы вызываете read (buf, offset, length), он не всегда читает байты длины каждый раз.Он просто читает, что доступно () в InputStream, и возвращает количество прочитанных байтов.Поэтому вам нужно продолжать вызывать read до тех пор, пока вы на самом деле не прочитаете байты длины.

int len = 0;
int expectedLength = sockInput.readInt();
byte[] buf = new byte[ expectedLength ];
while( len != buf.length ) {
   len += sockInput.read( buf, len, buf.length );
}

// now you have a buffer with expectedLength data in it.

Вы также можете посмотреть на использование DataInputStream.readFully (), обернув вашу

DataInputStream ds = new DataInputStream( sock.getInputStream() );
ds.readFully( buf, 0, buf.length );

http://docs.oracle.com/javase/6/docs/api/java/io/DataInputStream.html

Но если вы действительно только после String, вы должны сделать это:

Reader reader = new InputStreamReader( sockInput.getInputStream(), "UTF-8" );

Те же правила для чтения (char [], смещение, длина), что и для чтения (байт [], смещение, длина)

1 голос
/ 06 января 2012

Вам не важно, как TCP разбивает ваши сообщения на пакеты и сколько раз вы должны прочитать, чтобы получить полное сообщение.Просто прочитайте, пока не будет достигнут конец сообщения, а затем верните все байты сообщения.

Знание того, когда сообщение было прочитано полностью, зависит от вашего протокола.Вы можете выбрать отправку только одного сообщения для каждого соединения, или вы можете отправить длину сообщения перед сообщением, или использовать некоторый байт маркера.

Обратите внимание, что вы не должны использовать new String(byte[]) без указания кодировки(и используйте то же самое при вызове String.getBytes()), особенно если вы переводите с одного компьютера на другой, поскольку обе машины могут иметь различную кодировку по умолчанию.

...