Прежде чем углубиться в код, я задаю следующие основные вопросы:
Почему сервер не может подобрать загруженный клиентом контент? и
Какможно ли эффективно отлаживать такие структуры клиент-сервер (в их собственных потоках), поскольку пошаговая отладка через них не приводит к реалистичному или правильному поведению.
Я работаю в 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 () он также удаляет клиента на стороне сервера, который завершает соединение в целом, непреднамеренное поведение.