1

EDIT: While marked as a duplicate my situation is not the same as the other. I have discovered that serialized objects require the same package name on both the input and output streams. Mismatching package names was my problem.

I have a Java server and client. They are able to connect through sockets and use ObjectInputStream and ObjectOutputStream to send the object Packet back and forth. I have attempted to implement the client in Android. The Android client connects but I am unable to use the streams.

With my current implementation my Android client must be on the same network as my PC with the server running. My PC also has a static IP of 192.168.1.3. The error I get is

java.io.StreamCorruptedException: invalid type code: AC.

I'd post the code for my desktop server and client but I run out of characters. I got the code from here. I've modified that code so when the client connects no string is required. A user sends a ChatMessage (or Packet as I've renamed it) and the message contents are stored with the ClientThread. The client is able to request the last message they sent and the server returns it.

How do I correctly use the object streams with the Android client?

MainActivity:

package com.example.androidclient;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {
  Button btnGetLastMessage, btnSend, btnLogout;
  TextView textStatus;
  EditText textMessage;
  NetworkTask networktask;
  private Socket nsocket; // Network Socket
  private ObjectInputStream nis; // Network Input Stream
  private ObjectOutputStream nos; // Network Output Stream

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

    btnGetLastMessage = (Button) findViewById(R.id.btnGetLastMessage);
    btnSend = (Button) findViewById(R.id.btnSend);
    btnLogout = (Button) findViewById(R.id.btnLogout);
    textStatus = (TextView) findViewById(R.id.textStatus);
    textMessage = (EditText) findViewById(R.id.textMessage);

    btnGetLastMessage.setOnClickListener(btnGetLastMessageListener);
    btnSend.setOnClickListener(btnSendListener);
    btnLogout.setOnClickListener(btnLogoutListener);

    networktask = new NetworkTask();
    networktask.execute();
  }

  private OnClickListener btnLogoutListener = new OnClickListener() {
    public void onClick(View v) {
      networktask.SendDataToNetwork(new Packet(
          Packet.GET_LAST_MESSAGE));
    }
  };
  private OnClickListener btnGetLastMessageListener = new OnClickListener() {
    public void onClick(View v) {
      Packet msg = new Packet(Packet.GET_LAST_MESSAGE);
      networktask.SendDataToNetwork(msg);
    }
  };
  private OnClickListener btnSendListener = new OnClickListener() {
    public void onClick(View v) {
      textStatus.setText("Sending Message to AsyncTask.");
      Packet msg = new Packet(Packet.SEND_MESSAGE,
          textMessage.getText().toString());
      networktask.SendDataToNetwork(msg);
    }
  };

  public class NetworkTask extends AsyncTask<Void, byte[], Boolean> {

    @Override
    protected void onPreExecute() {
      Log.i("AsyncTask", "onPreExecute");
    }

    @Override
    protected Boolean doInBackground(Void... params) { // This runs on a
                              // different thread
      boolean result = false;
      try {
        Log.i("AsyncTask", "doInBackground: Creating socket");
        SocketAddress sockaddr = new InetSocketAddress("192.168.1.3",
            15000);
        nsocket = new Socket();
        nsocket.connect(sockaddr); // 10 second connection timeout

        if (nsocket.isConnected()) {
          // Creating both Data Stream
          try {
            nis = new ObjectInputStream(nsocket.getInputStream());
            nos = new ObjectOutputStream(nsocket.getOutputStream());
          } catch (IOException eIO) {
            Log.i("AsyncTask",
                "doInBackground: Exception creating new Input/output Streams: "
                    + eIO);
            eIO.printStackTrace();
            return false;
          }
          // creates the Thread to listen from the server

          Log.i("AsyncTask",
              "doInBackground: Socket created, streams assigned, listening from server");

          while (true) {
            Log.i("AsyncTask",
                "doInBackground: Waiting for data from the server...");
            try {
              Packet messageFromServer = (Packet) nis
                  .readObject();
              Log.i("ListenFromServer", "messageFromServer: "
                  + messageFromServer.getMessage());
              textStatus.setText("Last message: "
                  + messageFromServer.getMessage());
            } catch (IOException e) {
              Log.i("ListenFromServer",
                  "Server has close the connection: " + e);
              e.printStackTrace();
              break;
            } catch (ClassNotFoundException e2) {
              // Do nothing
            } catch (Exception e) {
              Log.i("ListenFromServer", "Generic exception: " + e);
              e.printStackTrace();
              break;
            }

          }
        }

      } catch (IOException e) {
        Log.i("AsyncTask", "doInBackground: IOException");
        e.printStackTrace();
        result = true;
      } catch (Exception e) {
        Log.i("AsyncTask", "doInBackground: Exception");
        e.printStackTrace();
        result = true;
      } finally {
        try {
          nis.close();
          nos.close();
          nsocket.close();
        } catch (IOException e) {
          e.printStackTrace();
        } catch (Exception e) {
          e.printStackTrace();
        }
        Log.i("AsyncTask", "doInBackground: Finished");
      }
      return result;
    }

    public void disconnect() {
      try {
        nis.close();
        nos.close();
        nsocket.close();
      } catch (Exception e) {
        Log.i("AsyncTask", "disconnect: Exception: " + e);
        e.printStackTrace();
      }
    }

    public void SendDataToNetwork(Packet msg) { // You run this from
                              // the
      // main thread.

      try {
        if (nsocket.isConnected()) {
          Log.i("AsyncTask",
              "SendDataToNetwork: Writing received message to socket");
          try {
            nos.writeObject(msg);
            nos.flush();
          } catch (IOException eIO) {
            Log.i("AsyncTask",
                "doInBackground:  Exception during login: "
                    + eIO);
            eIO.printStackTrace();
            nis.close();
            nos.close();
            nsocket.close();
          }
        } else {
          Log.i("AsyncTask",
              "SendDataToNetwork: Cannot send message. Socket is closed");
        }
      } catch (Exception e) {
        Log.i("AsyncTask",
            "SendDataToNetwork: Message send failed. Caught an exception");
        e.printStackTrace();
      }
    }

    @Override
    protected void onProgressUpdate(byte[]... values) {
      if (values.length > 0) {
        Log.i("AsyncTask", "onProgressUpdate: " + values[0].length
            + " bytes received.");
        textStatus.setText(new String(values[0]));
      }
    }

    @Override
    protected void onCancelled() {
      Log.i("AsyncTask", "Cancelled.");
    }

    @Override
    protected void onPostExecute(Boolean result) {
      if (result) {
        Log.i("AsyncTask", "onPostExecute: Completed with an Error.");
        textStatus.setText("There was a connection error.");
      } else {
        Log.i("AsyncTask", "onPostExecute: Completed.");
      }
    }
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    networktask.cancel(true); // In case the task is currently running
  }
}

activity_layout:

<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/textMessage"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:inputType="text"
        android:textSize="24sp" />

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

    <Button
        android:id="@+id/btnGetLastMessage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Get Last Message" >
    </Button>

    <Button
        android:id="@+id/btnLogout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Logout" >
    </Button>

    <TextView
        android:id="@+id/textStatus"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Status Goes Here"
        android:textSize="24sp" />

</LinearLayout>

android manifest:

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

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

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

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

     <application
        android:allowBackup="true"
        android:debuggable="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.androidclient.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>
RogerSmith
  • 204
  • 4
  • 11
  • how is `Packet` defined? Specifically, does it implement `Serializable`? Check out my answer [here](http://stackoverflow.com/a/15708748/1993996) – croyd Oct 09 '13 at 01:19
  • NB: (1) Create the `ObjectOutputStream` first, to avoid deadlock, and don't recreate it, to fix this problem. (2) There is no '10 second connection timeout' in your code. You haven't specified a timeout, so you get the default, which is around a minute. (3) Testing `isConnected()` immediately after calling `connect()` is pointless. It is connected. If it wasn't, an exception would have been thrown. – user207421 Oct 09 '13 at 01:29
  • @croyd If `Packet` wasn't `Serializable` OP would have got a `NotSerializableException,` not this one. – user207421 Oct 09 '13 at 01:34
  • @croyd If you checked the link and looked at the ChatMessage class you would have seen that it implements Serializable. – RogerSmith Oct 09 '13 at 02:51
  • @EJP I do create the streams just after connect. I have removed the new ObjectOutputStream from SendDataToNetwork and I no longer get the StreamCorruptedException error. Now as far as I can tell the client sent a message but the server doesn't respond. I don't get an error on either end and nothing happens on the server when a message is sent. – RogerSmith Oct 09 '13 at 03:11
  • You don't need to close anything in the send method. What does the server code look like? – user207421 Oct 09 '13 at 03:17
  • @EJP I've uploaded all of my code on my [dropbox](https://www.dropbox.com/sh/3cadtqij6s1ct29/rGnGvIC5y2). I run the server and client from their GUI classes then start the android app up. – RogerSmith Oct 16 '13 at 14:22
  • Your Dropbox is no permanent use to anybody. Post it here. Also the sending code. If you're still getting 'invalid type code: AC' you're still creating a new ObjectOutputStream in the middle somewhere. – user207421 Oct 16 '13 at 22:50

0 Answers0