ServerSocket не получает контент из Client Socket, несмотря на соединение - PullRequest
0 голосов
/ 23 сентября 2019

Прежде чем углубиться в код, я задаю следующие основные вопросы:

Почему сервер не может подобрать загруженный клиентом контент? и

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

Я работаю в Android Studio, поэтомуэто предназначено как упражнение для разработки приложений.

Далее вы увидите пользовательский Runnable, запускаемый извне созданным, например:

NetworkRunnable networkRunnable = new NetworkRunnable(serverIPAddress, port, testContent);
Thread networkThread = new Thread(networkRunnable);
networkThread.start();

Предполагается, чтосоздайте новый поток, в котором выполняется настраиваемый исполняемый процесс, который создает клиент Socket.Этот сокет-клиент подключается к серверу и отправляет некоторые данные + ожидает ответа впоследствии.Этот ответ с именем ReturnResponse возвращается в другом месте для дальнейшей обработки.

public class NetworkRunnable implements Runnable {


    private String jsonSendContent;
    private JSONArray ReturnResponse;
    private String serverIPAddress;
    private int SERVER_PORT;

    Socket socket;
    PrintWriter pw;
    BufferedReader br;


    public NetworkRunnable(String serverIPAddress, int port, String jsonSendContent){
        super();
        this.jsonSendContent = jsonSendContent;
        this.serverIPAddress = serverIPAddress;
        this.SERVER_PORT = port;

    }


    @Override
    public void run() {
        android.os.Debug.waitForDebugger();   // just for debugging purposes
        Log.d("BACKGROUND", "the run task is executed");
        System.out.println("CLIENT: run method started");


        try{  // we create a connection to the host server
            InetAddress hostAddress = InetAddress.getByName(serverIPAddress);
            socket = new Socket(hostAddress, SERVER_PORT);

            System.out.println("CLIENT: connected to " + socket.getRemoteSocketAddress());
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }


        JSONObject parsedContent = null;    
        JSONArray responses = null;

        try{
            System.out.println("CLIENT: prepare to send request");
            // we try to read the contents of the inputStream, meaning the content from the host and put it into a StringBuffer object that we return.
            pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
            pw.write(jsonSendContent); // send the json file as the only field in the string array
            pw.flush();

            System.out.println("CLIENT: request sent and flushed");

            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            StringBuffer buffer = new StringBuffer();
            String lineContent= "";

            System.out.println("CLIENT: preparing to read response");
            while((lineContent = br.readLine()) != null){
                buffer.append(lineContent+"\n");
                Log.d("CLIENT READLINE: " , ">>> " + lineContent);
            }

            String result = buffer.toString();  // the received result from the request

            System.out.println("CLIENT: read elements " + result);
            try { // get results overall
                parsedContent = new JSONObject(result);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            try { // get all the responses/parameters
                responses = parsedContent.getJSONArray("parameters");  // todo check the correct naming and structure, just to be sure
            } catch (JSONException e) {
                e.printStackTrace();
            }
            this.ReturnResponse =  responses;

        } catch (IOException e) {
            e.printStackTrace();
        } finally{  // make sure we close all our open connections
            if(socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(br != null){
                try{
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(pw != null){
                try {
                    pw.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            this.ReturnResponse = responses;

        }
    }
}

Далее вы увидите Test для метода run. Пожалуйста, игнорируйте фактические параметры в контенте, само утверждение не является проблемой Я использую проект, который включает DataProviders, который я пытаюсь передать в метод тестирования.

@RunWith(DataProviderRunner.class)
public class NetworkRunnableTester extends TesterFrame {

    private Socket mockSocket;
    private ServerSocket mockServerSocket;

    @DataProvider
    public static Object [] [] networkDataWithContent() throws JSONException {
        // preparation, not important
        return new Object [] [] {
                {"localhost", 12912 , sendContent, returnedContent }
        };
    }



    @Test
    @UseDataProvider("networkDataWithContent")
    public void runTester(String serverIPAddress, int port, String testContent, String expected)  {
        JSONArray responseSet;
            System.out.println("\nrunTester started\n");
            System.out.println("MAIN: prepare to launch server thread...");
        Thread serverThread = new Thread(this);
        serverThread.start();

            System.out.println("MAIN: prepare to create networkRunnable");
        NetworkRunnable networkRunnable = new NetworkRunnable(serverIPAddress, port, testContent);
        Thread networkThread = new Thread(networkRunnable);
            System.out.println("MAIN: Going to execute networkThread shortly after...");
        networkThread.start();

            System.out.println("MAIN: prepare to get response...");
        responseSet = networkRunnable.get();
            System.out.println("MAIN: responseSet gotten");
        Thread.sleep(5000);  // Without this, the Assertion would kill the threads immediately.
        Assert.assertEquals(expected, responseSet);
    }


    @Override
    public void run(){
        try {
                System.out.println("SERVER: started in its own thread!");

            mockServerSocket = new ServerSocket(12912, 0, InetAddress.getByName("localhost"));
                System.out.println("SERVER: created on " + InetAddress.getByName("localhost") + ":" + 12912);
            mockSocket = mockServerSocket.accept();
                System.out.println("SERVER: socket connected? " + mockSocket + " ? " +  mockSocket.isConnected());
            BufferedReader br = new BufferedReader(new InputStreamReader(mockSocket.getInputStream()));
            String readElements;
            StringBuffer stringBuffer = new StringBuffer();

                System.out.println("SERVER: preparing to read elements...");
            while((readElements = br.readLine() )!= null){
                stringBuffer.append(readElements);
            }
                System.out.println("SERVER: read elements" + stringBuffer.toString());
                Log.println(1, "SERVER RECEIVED: " , stringBuffer.toString());

            PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mockSocket.getOutputStream())));
            pw.write("{ parameters: test");
            pw.flush();
                System.out.println("SERVER: wrote and flushed response");

            // close connections
            br.close();
            mockSocket.close();
            mockServerSocket.close();
            pw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Когда я запускаю тест, фактические выходные данные отладки имеют следующий порядок:

runTester started

MAIN: prepare to launch server thread...
MAIN: prepare to create networkRunnable
SERVER: started in its own thread!
MAIN: Going to execute networkThread shortly after...
MAIN: prepare to get response...
MAIN: responseSet gotten
CLIENT: run method started
SERVER: created on localhost/127.0.0.1:12912
CLIENT: connected to localhost/127.0.0.1:12912
CLIENT: prepare to send request
SERVER: socket connected? Socket[addr=/127.0.0.1,port=53435,localport=12912] ? true
SERVER: preparing to read elements...
CLIENT: request sent and flushed
CLIENT: preparing to read response

Как вы можете видеть, Клиент ожидает ответа от Сервера,но сервер все еще ожидает что-то прочитать.Очевидно, что он не получил никакого контента от Клиента, хотя он был подключен.

Примечание. Мне очень жаль количество System.out.println, но, по-видимому, это единственный способ проверить выходные данные в Android Studio без запуска полного приложения в режиме отладки

Спасибо

Редактировать: я исправил это, решение было добавить разрыв строки "смысл \ n" в последнем сообщении, чтобы указать новую пустую строку.Только тогда он читает ноль и корректно закрывает поток.Чтобы исправить некоторые дополнительные проблемы с serverSocket, я добавил shutdownOutput () / shutdownInput () после записи в / чтения из потоков, в противном случае при использовании close () он также удаляет клиента на стороне сервера, который завершает соединение в целом, непреднамеренное поведение.

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