чете данни от сокет в нишката на сървъра с помощта на сокети

Приложението има клиентски и сървърни нишки. Клиентската нишка работи правилно. Има проблем по време на четене от сървъра това, което клиентът на другото приложение изпраща към моето приложение.

Има две изисквания за внедряване на този сървър

  1. Трябва да използвам UTF-16LE кодиране
  2. Не мога да използвам readLine, трябва само да използвам read byte/s

Опитах много примери, но изглежда нищо не работи правилно.

Ето кода на сървъра

private static final int    NUM_STATUSES    = 30;
private static final int    NUM_ERRORES     = 50;
private ServerSocket        _serverSocket;
private Socket              _socket;
private Handler             _handler;
private int                 _port;

//handler of main activity
public ServerNetworkThread()
{
    setName("ServerNetworkThread");
}

public void setHandler(Handler h)
{
    _handler = h;
}

@Override
public void run()
{

    _isWorking = true;
    try
    {
        _serverSocket = new ServerSocket();
        _serverSocket.setReuseAddress(true);
        _serverSocket.bind(new InetSocketAddress(_port));

        while (_isWorking)
        {
            _socket = _serverSocket.accept();
            _socket.setSoTimeout(Consts.CLIENT_SOCKET_TIMEOUT);

            readDataTest();

        }

    }
    catch (SocketTimeoutException e)
    {
        e.printStackTrace();
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }

}

private void readDataTest() throws IOException
{
    //          BufferedReader inFromClient = new BufferedReader(new InputStreamReader(_socket.getInputStream(),Charset.forName("UTF-16LE")));
    InputStream iStream = _socket.getInputStream();
    InputStreamReader in = new InputStreamReader(iStream, Charset.forName("UTF-16LE"));
    DataOutputStream outToClient = new DataOutputStream(_socket.getOutputStream());
    char[] buf = new char[iStream.available()];
    in.read(buf, 0, buf.length);
    String request = new String(buf);

    String responseStr = parseResponse(request);
    byte[] response = responseStr.getBytes("UTF-16LE");
    outToClient.write(response);
    outToClient.flush();
    outToClient.close();
    in.close();
    _socket.close();
    //          inFromClient.close();
}

Понякога получавам таймаут, когато се опитвам да прочета данните, които сървърът получава от клиента.

Благодаря за вашата помощ


person visionix visionix    schedule 07.03.2016    source източник
comment
може ли да публикувате проследяването на стека?   -  person Nadir    schedule 07.03.2016
comment
След като разпечатах това, което получавах, забелязах нещо странно: request=BB0006‹ENDL›0011‹EOF›└א└א└א└א└א└א└א└א└א└א└א└א└א└א└ א└א└א└א└א└א└א има много знаци в края, които не е необходимо да са там, може би има проблем с линия char[] buf = new char[iStream.available()] ;   -  person visionix visionix    schedule 07.03.2016
comment
В String request = new String(buf); изграждате низ, използвайки UTF-8 с байтове, идващи от UTF-16L. Посочете набора от знаци, когато конструирате този низ   -  person Nadir    schedule 07.03.2016
comment
Няма String конструктор, който може да получи char [] с кодиране, как мога да поправя това?   -  person visionix visionix    schedule 07.03.2016
comment
docs.oracle.com/javase/7/docs/api/java/lang/   -  person Nadir    schedule 07.03.2016
comment
Един голям проблем, който имате, е iStream.available(), който използвате за създаване на буфер и заявка. available ви казва само колко байта са налични, но не ви казва дали заявката ви е завършена. Имате нужда от някаква индикация за това колко байта за заявка ще получите или някакъв знак за край на заявката. Вашата заявка ще бъде непълна в противен случай повечето пъти, както и вашият отговор   -  person ata    schedule 07.03.2016
comment
Каква е причината за ограниченията да не се използва readLine() и т.н.?   -  person user207421    schedule 14.03.2016


Отговори (3)


Проблемът с вашия отговор не е някакъв митичен EOF символ, а че пренебрегвате броя на прочетените. Трябва да бъде

int count = in.read(buf);
if (count == -1)
    throw new EOFException();
String request = new String(buf, 0, count);`
person user207421    schedule 14.03.2016

Веднъж се занимавах с подобен проблем. Трябваше да получа низ, използващ UTF-16 с байтове, кодирани в UTF-8. Затова написах този метод, за да го направя:

//NOTE: 'charsetName' has to be a valid Name (see 'Charset'-Class in the API)
public String encode(char[] data, String charsetName)
{
    //Convert char[] to a String
    String charString = String.copyValueOf(data);
    String encoded = "";

    try 
    {
        //Since there is no constructor which lets you set char[] with encoding
        //convert your String to a byte-Array. There is a constructor which lets 
        //you set the Encoding for it.
        byte[] bytesEncoded = charString.getBytes(charsetName);

        //Construct a String using the encoding
        encoded = new String(bytesEncoded, charsetName);
    } 
    catch (UnsupportedEncodingException e) 
    {
        e.printStackTrace();
    }

    return encoded;
}

(Ще зададете "UTF-16LE" като charsetName)

Изглежда някак "мръсно" конвертиране на данни напред и назад, но за мен работи перфектно.

person MikeVe    schedule 07.03.2016
comment
за съжаление все още получавам някои странни знаци след ‹EOF›. но благодаря за помощта!. - person visionix visionix; 08.03.2016

В крайна сметка каква работа беше за мен:

  1. Винаги разпределям буфера с размер 1024, без да използвам iStream.available(), както Ata забеляза.
  2. След много опити не разбрах как да избягам всички знаци след "EOF". Просто разделих получения низ от EOF и взех първия фрагмент от низа и той работи добре. EOF символи край на заявката от клиента.

Това е кодът, който накрая използвах

private void readDataTest() throws IOException
{
    InputStream iStream = _socket.getInputStream();
    InputStreamReader in = new InputStreamReader(iStream, Charset.forName("UTF-16LE"));
    DataOutputStream outToClient = new DataOutputStream(_socket.getOutputStream());
    char[] buf = new char[1024];
    in.read(buf, 0, buf.length);
    String request = new String(buf);
    request = request.split(Consts.EOF)[0];

    String responseStr = parseResponse(request);
    byte[] response = responseStr.getBytes("UTF-16LE");
    outToClient.write(response);
    outToClient.flush();
    outToClient.close();
    in.close();
    _socket.close();
}
person visionix visionix    schedule 08.03.2016
comment
EOF не е знак в данните. - person user207421; 14.03.2016
comment
да, така е, можете да видите, че използвам Consts.EOF, този низ е ‹EOF› низ представлява края на получения низ, можете да видите това във втория коментар на първата публикация. - person visionix visionix; 15.03.2016
comment
Значи вашият код изпраща някакъв EOF знак? Не е показано никъде. - person user207421; 15.03.2016
comment
Както казах, можете да видите това във втория коментар на първия пост. След като разпечатах това, което получавам, забелязах нещо странно: request=BB0006‹ENDL›0011‹EOF›└א└א└א└א└א└א└א └א└א└א└א└א└א└א└א└א└א└א└א└א└א има много герои в края, които не е необходимо да са там, може би има проблем с линия char[] buf = нов char[iStream.available()]; - person visionix visionix; 15.03.2016