Сокет заблокирован при передаче объекта json с Java на Python

У меня проблема с сокетом Java-Python. Моя цель - отправить объект Json из приложения java в сценарий python через сокет tcp и получить ответ, но сокет заблокирован после отправки Json. Ниже приведен мой код:

try {
    Socket socket = new Socket(dstAddress, dstPort);
    is = new DataInputStream(socket.getInputStream());
    os = new DataOutputStream(socket.getOutputStream());
    PrintWriter pw = new PrintWriter(os, true);
    pw.println(jsonObject.toString());
    System.out.println("Send to the socket jsonObject.");

    BufferedReader in = new BufferedReader(new InputStreamReader(is));
    String response = in.readLine();
    System.out.println("Response: " + response);
    is.close();
    os.close();


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

В следующих строках код Python:

HOST = "192.168.1.101" #localhost
PORT = 7011
s = socket(AF_INET, SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)

while (1):
    print("\n\nAttending for client.....\n\n")
    conn, addr = s.accept()
    print("Connected by: " , addr) 

    data = ""
    while 1:
        temp = conn.recv(1024).decode()
        if not temp:
            break
        data = data + temp

    print("JSON Received!!!!!")

    imageJson = {}
    imageJson = json.loads(data)

    # responding to the client 
    response = DbImages[elem[0]]

    resp = "Prova"
    conn.send(resp.encode())

Если я завершу код java (ctrl + C), сокет выйдет из блока, и json поступит на python. В чем проблема? Кажется, проблема в.readLine (). Если я удалю этот оператор, сокет будет работать без блоков.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
105
2

Ответы 2

Ваш ответ не является строкой, поскольку кажется, что он не содержит окончания строки. Это означает, что readLine будет читать вечно.

Попробуйте добавить новую строку в свой ответ, чтобы обрадовать readLine:

resp = "Prova\n"

Ваш код Python ожидает завершения Java-стороны и отправляет EOF перед ответом (это то, что это означает для recv, пока вы не получите пустые байты).

Ваш код Java ожидает ответа от стороны Python перед закрытием сокета.

Итак, они оба ждут друг друга.


Удаление readLine означает, что код Java больше ничего не ждет, поэтому он просто зависает на коде Python, как только он завершает отправку, что решает проблему, но это не является большим решением, если вы на самом деле нужен был ответ.


Итак, что они должны делать? Что ж, есть несколько разных вариантов.

  • Используйте протокол с фреймами, при котором сторона Java либо отправляет разделитель «сообщение готово» после каждого сообщения, либо отправляет заголовок (например, с длиной сообщения в байтах) перед каждым из них. Таким образом, код Python может считываться до тех пор, пока не будет получено полное сообщение, а не до EOF.
    • Если вы кодируете свой JSON в компактном формате со всем, кроме печатаемого ASCII с экранированием, тогда разделителем может быть просто новая строка (в этот момент вы используете JSONlines в качестве протокола), а код Python может использовать makefile в сокете и вызывать readline вместо того, чтобы перебирать recv.
  • Обманывайте и используйте JSON, как если бы это был протокол с фреймами. Это не так, но пока единственными значениями верхнего уровня, которые вы когда-либо отправляете, являются объекты и массивы, это работает. Затем код Python может использовать raw_decode (см. Документацию модуля json) после каждого приема до тех пор, пока он не будет успешным.
  • Если вы собираетесь отправить только одно сообщение, вы можете просто наполовину выключить сокет (закрыть конец записи) из Java, и тогда Python получит свой EOF и ответит на все еще открытой другой стороне сокета. (Это может показаться хакерским, но на самом деле это совершенно обычное явление - именно так традиционно работают веб-браузеры, хотя HTTP 1.1 немного усложнил задачу.)

Другие вопросы по теме