编辑:虽然标记为重复,但我的情况与其他情况不同。我发现序列化对象在输入和输出流上都需要相同的包名称。不匹配的包名称是我的问题。
我有一个 Java 服务器和客户端。它们能够通过套接字连接并使用 ObjectInputStream 和 ObjectOutputStream 来回发送对象数据包。我试图在 Android 中实现客户端。Android 客户端连接但我无法使用流。
在我当前的实现中,我的 Android 客户端必须与我的 PC 位于同一网络上,并且服务器正在运行。我的电脑也有一个静态 IP 192.168.1.3。我得到的错误是
java.io.StreamCorruptedException:无效类型代码:AC。
我会发布我的桌面服务器和客户端的代码,但我的字符用完了。我从这里得到了代码。我已经修改了该代码,因此当客户端连接时不需要字符串。用户发送一个 ChatMessage(或我重命名的 Packet),消息内容与 ClientThread 一起存储。客户端能够请求他们发送的最后一条消息,服务器将其返回。
如何在 Android 客户端中正确使用对象流?
主要活动:
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
}
}
活动布局:
<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>
安卓清单:
<?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>