简体   繁体   中英

Android socket client - can't send messages

First off, I'm a complete newbie to Android, Java and posting on Stacks Overflow so apologies if I'm doing anything wrong!

I'm trying to create a simple app for a project that utilises sockets. I want to set up a client on an Android device that sends commands to a server running on a PC. I've written my server in Python and have tested it, so I know that side of the project works. I'm having issues with the implementation of the Android app.

I followed this guide to write my client app: https://examples.javacodegeeks.com/android/core/socket-core/android-socket-example/

When I run my app, my server acknowledges that a client has connected to it. However, when I try to send data, nothing is received by the server. This is what my code looks like (it's pretty much the same as that in the link above):

MainActivity.java

package com.example.user.sockettest;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

public class MainActivity extends Activity {


    private Socket socket;

    private static final int SERVERPORT = 8000;
    private static final String SERVER_IP = "192.168.0.17";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread(new ClientThread()).start();
    }

    public void onClick(View view) {
        try {
            EditText et = (EditText) findViewById(R.id.editText);
            String str = et.getText().toString();
            PrintWriter out = new PrintWriter(new BufferedWriter(
                    new OutputStreamWriter(socket.getOutputStream())),
                    true);
            out.println(str);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    class ClientThread implements Runnable {

        @Override
        public void run() {

            try {
                InetAddress serverAddr = InetAddress.getByName(SERVER_IP);

                socket = new Socket(serverAddr, SERVERPORT);

            } catch (UnknownHostException e1) {
                e1.printStackTrace();
            } catch (IOException e1) {
                e1.printStackTrace();
            }

        }

    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >

        <EditText
            android:id="@+id/editText"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="TestData" >
        </EditText>

        <Button
            android:id="@+id/myButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="onClick"
            android:text="Send" >
        </Button>

    </LinearLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.user.sockettest">

    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <uses-permission android:name="android.permission.INTERNET" >
    </uses-permission>

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
    </uses-permission>

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity android:name="com.example.user.sockettest.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

As you can see, I've set permissions as others have recommended on other threads but this does not seem to help. The socket runs on a separate thread so I doubt it's a blocking issue either.

My experience with socket programming is mainly in Python so I'm sure I'm missing something very basic in its Java implementation!

Any help or pointers would be really appreciated!

EDIT: Update code that is working now, thanks to Gabe Sechan's answer

public class MainActivity extends Activity {


    private Socket socket;
    boolean sendData = false;   // Flag to indicate whether data should be sent
    String message;

    private static final int SERVERPORT = 8000;
    private static final String SERVER_IP = "192.168.0.17";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread(new ClientThread()).start();
    }

    public void onClick(View view) {
        EditText et = (EditText) findViewById(R.id.editText);
        message = et.getText().toString();
        sendData = true;
    }

    class ClientThread implements Runnable {

        @Override
        public void run() {
            try {
                InetAddress serverAddr = InetAddress.getByName(SERVER_IP);

                socket = new Socket(serverAddr, SERVERPORT);
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                // Loop forever checking if a message needs to be send
                while (socket.isConnected()){
                    if (sendData){
                        // If a message is ready to be sent, call sendMessage method
                        sendMessage();
                    }
                }
            } catch (UnknownHostException e1) {
                e1.printStackTrace();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }

        private void sendMessage(){
            // Send message over socket
            try {
                PrintWriter out = new PrintWriter(socket.getOutputStream());
                out.println(message);
                out.flush();
                // Reset flag
                sendData=false;
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

I'm surprised you aren't crashing. The click handler runs on the main thread. The main thread can't do network IO- it should throw an exception to try. The BufferedWriter might be saving you there- it may not be writing to the actual socket and buffering everything if the messages are small, because you aren't flushing the stream.

So the first thing you need to do is do the writes on another thread- probably your ClientThread, and use some form of message passing to send write commands to it. The second thing you need is to simplify your output writers- you really don't need to wrap it in anything, just writing directly to the output stream is sufficient for your use.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM