我正在使用一些示例代码,该代码使我可以将消息从Python客户端发送到Android服务器(TCP)。但是,仅在关闭客户端后,该消息才会显示在Android仿真器上。
我可能缺少tcp套接字(首次使用和实现)背后的一些基本知识。
我的主要目的是使Android App中的按钮可以在单击时将不同的消息发送到单独的Linux系统上的Python客户端,并且Python客户端在收到该消息后会发送回确认。
以下是我的代码
服务器.java
package test.server2; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.util.Enumeration; public class Server { MainActivity activity; ServerSocket serverSocket; String message = ""; static final int socketServerPORT = 8080; public Server(MainActivity activity) { this.activity = activity; Thread socketServerThread = new Thread(new SocketServerThread()); socketServerThread.start(); } public int getPort() { return socketServerPORT; } public void onDestroy() { if (serverSocket != null) { try { serverSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private class SocketServerThread extends Thread { int count = 0; @Override public void run() { try { // create ServerSocket using specified port serverSocket = new ServerSocket(socketServerPORT); while (true) { // block the call until connection is created and return // Socket object Socket socket = serverSocket.accept(); count++; InputStream message2 = socket.getInputStream(); final String messageReceived = convertToString(message2); activity.runOnUiThread(new Runnable() { @Override public void run() { activity.msg.setText(messageReceived); } }); //SocketServerReplyThread socketServerReplyThread = // new SocketServerReplyThread(socket, count); //socketServerReplyThread.run(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); message += "Something wrong! " + e.toString() + "\n"; } activity.runOnUiThread(new Runnable() { @Override public void run() { activity.msg.setText(message); } }); } } private class SocketServerReplyThread extends Thread { private Socket hostThreadSocket; int cnt; SocketServerReplyThread(Socket socket, int c) { hostThreadSocket = socket; cnt = c; } @Override public void run() { OutputStream outputStream; String msgReply = "Hello from Server, you are #" + cnt; try { outputStream = hostThreadSocket.getOutputStream(); PrintStream printStream = new PrintStream(outputStream); printStream.print(msgReply); printStream.close(); message += "replayed: " + msgReply + "\n"; activity.runOnUiThread(new Runnable() { @Override public void run() { activity.msg.setText(message); } }); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); message += "Something wrong! " + e.toString() + "\n"; } activity.runOnUiThread(new Runnable() { @Override public void run() { activity.msg.setText(message); } }); } } private String convertToString(InputStream message) { BufferedReader reader = new BufferedReader(new InputStreamReader(message)); StringBuilder stringbuilder = new StringBuilder(); String line = null; try { while ((line = reader.readLine()) != null) { //stringbuilder.append(line).append('\n'); stringbuilder.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { try { message.close(); //reader.close(); } catch (IOException e) { e.printStackTrace(); } } return stringbuilder.toString(); } public String getIpAddress() { String ip = ""; try { Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface .getNetworkInterfaces(); while (enumNetworkInterfaces.hasMoreElements()) { NetworkInterface networkInterface = enumNetworkInterfaces .nextElement(); Enumeration<InetAddress> enumInetAddress = networkInterface .getInetAddresses(); while (enumInetAddress.hasMoreElements()) { InetAddress inetAddress = enumInetAddress .nextElement(); if (inetAddress.isSiteLocalAddress()) { ip += "Server running at : " + inetAddress.getHostAddress(); } } } } catch (SocketException e) { // TODO Auto-generated catch block e.printStackTrace(); ip += "Something Wrong! " + e.toString() + "\n"; } return ip; } }
我已将对SocketServerReplyThread的调用及相关内容注释掉了,因为这导致了错误。注释掉该内容会导致从Python客户端接收消息,但是只有在关闭客户端套接字后,它才会显示在Android仿真器上。我希望它是连续的,以便每当客户端发送一条消息(并且android服务器正在侦听)时,该消息就会被打印出来。
MainActivity.java
package test2.server; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; public class MainActivity extends AppCompatActivity { Server server; TextView infoip, msg; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); infoip = (TextView) findViewById(R.id.infoip); msg = (TextView) findViewById(R.id.msg); server = new Server(this); infoip.setText(server.getIpAddress() + ":" + server.getPort()); } @Override protected void onDestroy() { super.onDestroy(); server.onDestroy(); } }
Python客户端
#!/usr/bin/python import socket import time s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = "127.0.0.1" port = 4534 s.connect((host, port)) s.send("Thank you for connecting" + '\n') time.sleep(10) #added to check if it gets displayed before closing or not s.close()
默认情况下,套接字阻止。因此,当您调用readline时,在关闭套接字之前,它将永远不会返回null。按照编码,您的代码将等待,直到从客户端读取了所有数据并且客户端关闭了连接,然后将其变成1个大字符串并从convertToString返回。您需要重新配置,以便处理每个readline调用的结果并显示它,而不是将所有内容都视为1个巨型字符串。