Сокет Java UDP - данные остаются на стороне сервера - PullRequest
3 голосов
/ 23 января 2012

Я реализую действительно базовую модель сервер-клиент в Java, используя UDP-сокеты, и я столкнулся с действительно странной проблемой.

Все, что я хочу сделать, - это позволить пользователю (клиенту) отправитьсообщение на сервер, а затем сервер напечатает его.

У меня есть пример, но я что-то упустил, так как у меня есть следующая проблема:

Если клиент отправляет сообщение «a»сервер он получает правильно.Если клиент отправляет сообщение «bbb» на сервер, оно принимается правильно.Если клиент отправляет сообщение «c» на сервер, то сервер напечатает «cbb» в качестве полученного сообщения.

Кажется, что сервер действительно очищает какой-то буфер, когда получает новое сообщение.

Это код, который я использую:

Сервер

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;



public class UDPServer {
public static void main(String args[]) throws Exception {
    byte[] receive_data = new byte[256];
    int recv_port;

    DatagramSocket server_socket = new DatagramSocket(5000);

    System.out.println("Server - Initialized server. Waiting for client on port 5000");

    while (true) {
        // System.out.println("Server - Listening for connections...");
        DatagramPacket receive_packet = new DatagramPacket(receive_data, receive_data.length);

        server_socket.receive(receive_packet);

        String data = new String(receive_packet.getData());

        InetAddress IPAddress = receive_packet.getAddress();

        recv_port = receive_packet.getPort();

        if (data.equals("q") || data.equals("Q")) {
            System.out.println("Server - Exiting !");
            break;
        } else {
            System.out.println("Server - Client from IP " + IPAddress + " @ port " + recv_port + " said : " + data + " (length: " + receive_packet.getLength() + ")");
        }
    }
}
}

Клиент

public class UDPClient {
public static void main(String args[]) throws Exception {
    byte[] send_data = new byte[256];

    BufferedReader infromuser = new BufferedReader(new InputStreamReader(System.in));

    DatagramSocket client_socket = new DatagramSocket();

    InetAddress IPAddress = InetAddress.getByName("localhost");

    System.out.println("Client - Initialized the client...");

    while (true) {
        System.out.print("Client - Type Something (q or Q to quit): ");

        String data = infromuser.readLine();

        if (data.equals("q") || data.equals("Q")) {
            System.out.println("Client - Exited !");
            DatagramPacket send_packet = new DatagramPacket(send_data, send_data.length, IPAddress, 5000);
            System.out.println("Client - Sending data : <" + data + ">");
            client_socket.send(send_packet);
            break;
        } else {
            send_data = data.getBytes();
            DatagramPacket send_packet = new DatagramPacket(send_data, send_data.length, IPAddress, 5000);
            System.out.println("Client - Sending data : <" + data + ">");
            client_socket.send(send_packet);
        }
    }

    client_socket.close();
}
}

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

Просто чтобы прояснить, я запускаю и сервер, и клиент на одной машине(mac) на разных терминалах, на случай, если это все равно повлияет на ситуацию.

Любая помощь будет принята с благодарностью.

EDIT

.И я возвращаюсь, чтобы ответить на свой вопрос.Проблема заключалась в том, что я не определял объем данных, которые серверный сокет должен ожидать прочитать.Поэтому, когда я меняю

String data = new String(receive_packet.getData());

на

String data = new String(receive_packet.getData(), 0, receive_packet.getLength());

, все работает гладко.

Только для дальнейшего использования и для людей, которые могут столкнуться с той же проблемой:)

Ответы [ 3 ]

4 голосов
/ 23 января 2012

Когда вы строите String на основе результата, вы в настоящее время игнорируете длину полученного пакета.

После использования DataSocket.receive(DatagramPacket) длина DatagramPacket должна быть установлена ​​равной фактически полученной длине:

Поле длины объекта пакета дейтаграммы содержит длину полученное сообщение. Если сообщение длиннее пакета длина сообщения усекается.

Это должно решить проблему на принимающей стороне:

String data = new String(receive_packet.getData(), 0, receive_packet.getLength());

Чтобы это работало, вам также необходимо убедиться, что отправленные данные имеют правильный размер. В частности, не используйте send_data.length для создания исходящего DatagramPacket. Это всегда будет использовать всю длину буфера). Параметр длины не всегда должен быть send_data.length (иначе конструктор получит его сам из массива), он предназначен для фактической полезной длины сообщения в этом массиве.

3 голосов
/ 23 января 2012

При первом вызове это выглядит как receive_data:

 --------------
|"a"|    |    |
 --------------

На ваш второй звонок:

 --------------
|"b"|"b"| "b" |             notice that the "a" in data_receive was overwritten
 --------------

При третьем звонке вы отправляете только одно письмо, поэтому единственная часть массива, которая перезаписывается, это первый элемент:

 --------------
|"c"|"b"| "b" | 
 --------------

Это происходит из-за того, что в массиве receive_data между сообщениями серверу остаются данные, простой способ обойти это - просто инициализировать новый массив внутри цикла приема. Таким образом, каждый раз, когда вы получите сообщение, вас будет ждать новый массив.

while (true) 
{
    byte[] receive_data = new byte[256];
    ......
}
0 голосов
/ 03 августа 2015

Чтобы решить эту проблему, вы должны использовать длину receive_packet для создания строки или массива.
Для более высокой производительности на стороне сервера лучше инициализировать receive_packet перед секцией whileи сбросьте его длину в конце секции while для повторного использования в цикле: receive_packet.setLength(buffer.length);

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...