Garth Garth - 2 months ago 17
Python Question

How to connect Android app to python-socketio backend?

I am currently running a Python SocketIO server that connects perfectly to my JavaScript Client. I am using the socketio android example chat app to write the Android code, it worked perfectly with a NodeJS server but when I change over to using the Python server it won't connect.

How can I connect to the Ptyhon-SocketIO server from Android?

Android code:

public class HomeActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {

private final String TAG = "MainActivity";

Button btnCore0, btnCore1, btnCPUUsage;
private ProgressBar progressBar;

private Socket mSocket;

{
try {
mSocket = IO.socket(Constants.SERVER_URL);
} catch (URISyntaxException e) {
Log.e(TAG, e.getMessage());
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
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();
}
});

DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();

NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);

btnCore0 = (Button) findViewById(R.id.btnCore0);
btnCore1 = (Button) findViewById(R.id.btnCore1);
btnCPUUsage = (Button) findViewById(R.id.btnCPUUsage);
progressBar = (ProgressBar) findViewById(R.id.progressBar);

// Make buttons invisible
btnCore0.setVisibility(View.INVISIBLE);
btnCore1.setVisibility(View.INVISIBLE);
btnCPUUsage.setVisibility(View.INVISIBLE);
// Make progress bar visible
progressBar.setVisibility(View.VISIBLE);

mSocket.on("status-update", onNewMessage);
mSocket.on(Socket.EVENT_DISCONNECT, onSocketDisconnected);
mSocket.connect();
}

private Emitter.Listener onNewMessage = new Emitter.Listener() {
@Override
public void call(final Object... args) {
HomeActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "New message 090909***");
JSONObject data = (JSONObject) args[0];
int core0 = 0;
int core1 = 0;
int cpu_usage_in = 0;
try {
core0 = data.getInt("core0_in");
core1 = data.getInt("core1_in");
cpu_usage_in = data.getInt("cpu_usage_in");
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
}

btnCore0.setText(getResources().getString(R.string.core0, String.valueOf(core0)));
btnCore1.setText(getResources().getString(R.string.core1, String.valueOf(core1)));
btnCPUUsage.setText(getResources().getString(R.string.cpu_usge, String.valueOf(cpu_usage_in)));

updateButtonBackgroundColor(btnCore0, core0);
updateButtonBackgroundColor(btnCore1, core1);
updateButtonBackgroundColor(btnCPUUsage, cpu_usage_in);

onServerDataReceived();
}
});
}
};


Next is the Pyhton server that emits every second. This, I know works fine as I can connect to it from a JavaScript app.
Python code:

from flask import Flask, render_template
from flask_socketio import SocketIO
from gcm import GCM

eventlet.monkey_patch()
app = Flask(__name__)
socket = SocketIO(app, logger=True, engineio_logger=True)

class Server(threading.Thread):
def __init__(self, thread_id):
threading.Thread.__init__(self)
self.threadID = thread_id

def run(self):
print("Starting " + self.name)
serve()
print("Exiting " + self.name)


def serve():
if __name__ == '__main__':
eventlet.wsgi.server(eventlet.wrap_ssl(eventlet.listen(('', 8000)), certfile='/home/garthtee/cert.pem', keyfile='/home/garthtee/privkey.pem'), app)

server_thread = Server("Server-thread")
server_thread.start()
threads.append(server_thread)
print("Started @ " + str(get_time()))
while True:
sensors.init()
try:
for chip in sensors.iter_detected_chips():
# print('%s at %s' % (chip, chip.adapter_name))
for feature in chip:
if feature.label == 'Core 0':
core0 = feature.get_value()
elif feature.label == 'Core 1':
core1 = feature.get_value()
for x in range(1):
cpu_usage = str(psutil.cpu_percent(interval=1))
finally:
socket.emit('status-update', {'core0_in': core0, 'core1_in': core1, 'cpu_usage_in': cpu_usage, 'users': users})

alert_checker(avg_temp, users)
sensors.cleanup()
time.sleep(1)


The following error shows up:

SSLError: [SSL: SSL_HANDSHAKE_FAILURE] ssl handshake failure (_ssl.c:1754)

Answer

I downloaded the SocketIO python library from Github

I modified the example code like this:

import socketio
import eventlet
import eventlet.wsgi
from flask import Flask, render_template

sio = socketio.Server()
app = Flask(__name__)

@app.route('/')
def index():
    """Serve the client-side application."""
    return render_template('index.html')

@sio.on('connect', namespace='/')
def connect(sid, environ):
    print("connect ", sid)

@sio.on('add user', namespace='/')
def login(sid, environ):
    print("login ", sid)
    sio.emit('login', room=sid)

@sio.on('new message', namespace='/')
def message(sid, data):
    print("message ", data)
    sio.emit('reply', room=sid)

@sio.on('disconnect', namespace='/')
def disconnect(sid):
    print('disconnect ', sid)

if __name__ == '__main__':
    # wrap Flask application with engineio's middleware
    app = socketio.Middleware(sio, app)

    # deploy as an eventlet WSGI server
    eventlet.wsgi.server(eventlet.listen(('', 8000)), app)

Then I cloned the Android example chat project, and the only thing what I changed in the Constants.java:

public static final String CHAT_SERVER_URL = "http://MY_LOCAL_IP:8000";

And the Android app can connect. I see it in the app, and also in the python console. If you remove some unnecessary parsing part (the app is crashing, because the response is different), you can also see your messages in python.

Have you tried to run your server app without SSL first?

Maybe that is the problem. On Android you can use IO.setDefaultSSLContext(SSLContext sslContext) to setup SSL.

Comments