Android C/S 使用带有序列化对象的 ObjectInputStream 和 ObjectOutputStream class
Android C/S using ObjectInputStream and ObjectOutputStream with a Serializable class
在桌面上,我有一个完美工作的多线程 client/server 项目,使用 ObjectInputStream/ ObjectOutputStream 和一个实现可序列化的 class Protocol。这个class在服务端和客户端都用到了。作为学习经验,我决定在 Android Studio 上实施客户端。我创建了以下 AsyncTasks:
OpenSocket – OpenSocket extends AsyncTask<String, Integer, Socket>
OpenObjectInputStream – OpenObjectInputStream extends AsyncTask<Socket, Integer, ObjectInputStream>
OpenObjectOutputStream – OpenObjectOutputStream extends AsyncTask<Socket, Integer, ObjectOutputStream>
ReadFromServer - ReadFromServer extends AsyncTask<ObjectInputStream, Integer, Object>
写入服务器 - WriteToServer extends AsyncTask<ObjectOutputStream, Integer, Boolean>
在我的 MainActivity 上,我有一个连接按钮的方法:
public void ligarBtClick(View v) {
String[] params = new String[]{
server.getText().toString(),
port.getText().toString()
};
AsyncTask<String, Integer, Socket> openSocket = new OpenSocket().execute(params);
try {
socket = openSocket.get();
if (socket != null) {
AsyncTask<Socket, Integer, ObjectOutputStream> openObjectOutputStream = new OpenObjectOutputStream(xChange).execute(socket);
output = openObjectOutputStream.get();
AsyncTask<Socket, Integer, ObjectInputStream> openObjectInputStream = new OpenObjectInputStream(xChange).execute(socket);
input = openObjectInputStream.get();
AsyncTask<ObjectInputStream, Integer, Object> readFromServer = new ReadFromServer(xChange).execute(input);
msgFromServer = (Protocolo) readFromServer.get();
fromServer.append("SERVER:\t" + msgFromServer.getType() + ": " + msgFromServer.getMessage() + "\n");
toServer.requestFocus();
desligarBt.setEnabled(true);
ligarBt.setEnabled(false);
enviarBt.setEnabled(true);
} else {
fromServer.append("LOG:\tCould not connect to " + params[0] + ":" + params[1] + "\n");
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
我连接成功,我正在获取输入和输出流,并且使用 Wireshark,我可以看到服务器正在向客户端发送问候语,客户端已确认。 ReadFromServer AsyncTask 的相关部分是:
@Override
protected Object doInBackground(ObjectInputStream... params) {
Object msgFromServer = null;
Message msg = Message.obtain();
try {
msgFromServer = params[0].readObject();
msg.what = 5;
} catch (IOException e) {
e.printStackTrace();
msg.what = 6;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
xchange.sendMessage(msg);
return msgFromServer;
}
我的应用程序在我 运行 ReadFromServer 时崩溃,更具体地说,当它遇到此行时 msgFromServer = params[0].readObject();
它会崩溃并显示以下消息:
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: java.lang.ClassNotFoundException: Protocolo
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.lang.Class.classForName(Native Method)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.lang.Class.forName(Class.java:251)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:2265)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1641)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:657)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:1784)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:761)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1985)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1942)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at pt.enta.jdm.tcpclientobject.ReadFromServer.doInBackground(ReadFromServer.java:30)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at pt.enta.jdm.tcpclientobject.ReadFromServer.doInBackground(ReadFromServer.java:14)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at android.os.AsyncTask.call(AsyncTask.java:288)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:237)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:231)
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.lang.Thread.run(Thread.java:841)
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: Caused by: java.lang.NoClassDefFoundError: Protocolo
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: ... 17 more
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: Caused by: java.lang.ClassNotFoundException: Didn't find class "Protocolo" on path: DexPathList[[zip file "/data/app/pt.enta.jdm.tcpclientobject-6.apk"],nativeLibraryDirectories=[/data/app-lib/pt.enta.jdm.tcpclientobject-6, /vendor/lib, /system/lib]]
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: ... 17 more
06-20 12:34:08.755 12591-12591/pt.enta.jdm.tcpclientobject D/AndroidRuntime: Shutting down VM
06-20 12:34:08.755 12591-12591/pt.enta.jdm.tcpclientobject W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x41f79bc0)
06-20 12:34:08.755 12591-12591/pt.enta.jdm.tcpclientobject E/AndroidRuntime: FATAL EXCEPTION: main
Process: pt.enta.jdm.tcpclientobject, PID: 12591
java.lang.IllegalStateException: Could not execute method for android:onClick
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:293)
at android.view.View.performClick(View.java:4508)
at android.view.View$PerformClick.run(View.java:18675)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5584)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
at android.view.View.performClick(View.java:4508)
at android.view.View$PerformClick.run(View.java:18675)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5584)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at pt.enta.jdm.tcpclientobject.MainActivity.ligarBtClick(MainActivity.java:66)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
at android.view.View.performClick(View.java:4508)
at android.view.View$PerformClick.run(View.java:18675)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5584)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
at dalvik.system.NativeStart.main(Native Method)
它抱怨的class是服务器中存在的class(不在客户端);我在服务器中更改了 class 的名称,果然它抱怨找不到新名称。想不通这个。
谢谢!
找到了解决我自己问题的方法。服务器和客户端都使用 class Protocol。 class 必须在客户端和服务器中的同一个包 中。我在客户端和服务器中都有 class,但是(据我所知这是正常的)在不同的包中。
谢谢!
在桌面上,我有一个完美工作的多线程 client/server 项目,使用 ObjectInputStream/ ObjectOutputStream 和一个实现可序列化的 class Protocol。这个class在服务端和客户端都用到了。作为学习经验,我决定在 Android Studio 上实施客户端。我创建了以下 AsyncTasks:
OpenSocket – OpenSocket extends AsyncTask<String, Integer, Socket>
OpenObjectInputStream – OpenObjectInputStream extends AsyncTask<Socket, Integer, ObjectInputStream>
OpenObjectOutputStream – OpenObjectOutputStream extends AsyncTask<Socket, Integer, ObjectOutputStream>
ReadFromServer - ReadFromServer extends AsyncTask<ObjectInputStream, Integer, Object>
写入服务器 - WriteToServer extends AsyncTask<ObjectOutputStream, Integer, Boolean>
在我的 MainActivity 上,我有一个连接按钮的方法:
public void ligarBtClick(View v) {
String[] params = new String[]{
server.getText().toString(),
port.getText().toString()
};
AsyncTask<String, Integer, Socket> openSocket = new OpenSocket().execute(params);
try {
socket = openSocket.get();
if (socket != null) {
AsyncTask<Socket, Integer, ObjectOutputStream> openObjectOutputStream = new OpenObjectOutputStream(xChange).execute(socket);
output = openObjectOutputStream.get();
AsyncTask<Socket, Integer, ObjectInputStream> openObjectInputStream = new OpenObjectInputStream(xChange).execute(socket);
input = openObjectInputStream.get();
AsyncTask<ObjectInputStream, Integer, Object> readFromServer = new ReadFromServer(xChange).execute(input);
msgFromServer = (Protocolo) readFromServer.get();
fromServer.append("SERVER:\t" + msgFromServer.getType() + ": " + msgFromServer.getMessage() + "\n");
toServer.requestFocus();
desligarBt.setEnabled(true);
ligarBt.setEnabled(false);
enviarBt.setEnabled(true);
} else {
fromServer.append("LOG:\tCould not connect to " + params[0] + ":" + params[1] + "\n");
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
我连接成功,我正在获取输入和输出流,并且使用 Wireshark,我可以看到服务器正在向客户端发送问候语,客户端已确认。 ReadFromServer AsyncTask 的相关部分是:
@Override
protected Object doInBackground(ObjectInputStream... params) {
Object msgFromServer = null;
Message msg = Message.obtain();
try {
msgFromServer = params[0].readObject();
msg.what = 5;
} catch (IOException e) {
e.printStackTrace();
msg.what = 6;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
xchange.sendMessage(msg);
return msgFromServer;
}
我的应用程序在我 运行 ReadFromServer 时崩溃,更具体地说,当它遇到此行时 msgFromServer = params[0].readObject();
它会崩溃并显示以下消息:
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: java.lang.ClassNotFoundException: Protocolo
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.lang.Class.classForName(Native Method)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.lang.Class.forName(Class.java:251)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:2265)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1641)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:657)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:1784)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:761)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1985)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1942)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at pt.enta.jdm.tcpclientobject.ReadFromServer.doInBackground(ReadFromServer.java:30)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at pt.enta.jdm.tcpclientobject.ReadFromServer.doInBackground(ReadFromServer.java:14)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at android.os.AsyncTask.call(AsyncTask.java:288)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:237)
06-20 12:34:08.745 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:231)
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.lang.Thread.run(Thread.java:841)
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: Caused by: java.lang.NoClassDefFoundError: Protocolo
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: ... 17 more
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: Caused by: java.lang.ClassNotFoundException: Didn't find class "Protocolo" on path: DexPathList[[zip file "/data/app/pt.enta.jdm.tcpclientobject-6.apk"],nativeLibraryDirectories=[/data/app-lib/pt.enta.jdm.tcpclientobject-6, /vendor/lib, /system/lib]]
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
06-20 12:34:08.755 12591-13006/pt.enta.jdm.tcpclientobject W/System.err: ... 17 more
06-20 12:34:08.755 12591-12591/pt.enta.jdm.tcpclientobject D/AndroidRuntime: Shutting down VM
06-20 12:34:08.755 12591-12591/pt.enta.jdm.tcpclientobject W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x41f79bc0)
06-20 12:34:08.755 12591-12591/pt.enta.jdm.tcpclientobject E/AndroidRuntime: FATAL EXCEPTION: main
Process: pt.enta.jdm.tcpclientobject, PID: 12591
java.lang.IllegalStateException: Could not execute method for android:onClick
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:293)
at android.view.View.performClick(View.java:4508)
at android.view.View$PerformClick.run(View.java:18675)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5584)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
at android.view.View.performClick(View.java:4508)
at android.view.View$PerformClick.run(View.java:18675)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5584)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at pt.enta.jdm.tcpclientobject.MainActivity.ligarBtClick(MainActivity.java:66)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
at android.view.View.performClick(View.java:4508)
at android.view.View$PerformClick.run(View.java:18675)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5584)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
at dalvik.system.NativeStart.main(Native Method)
它抱怨的class是服务器中存在的class(不在客户端);我在服务器中更改了 class 的名称,果然它抱怨找不到新名称。想不通这个。
谢谢!
找到了解决我自己问题的方法。服务器和客户端都使用 class Protocol。 class 必须在客户端和服务器中的同一个包 中。我在客户端和服务器中都有 class,但是(据我所知这是正常的)在不同的包中。
谢谢!