上一篇,我们遗留了一个问题,那就是Python的pickle模块,序列化后的字节流bytes,如果通过socket传给Java,Java可以反序列化吗?
我们看下demo案列(案列很简单,就是简单的信息传输,不涉及多线程和回写),验证一下就知道了:
Java服务端demo
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Test2 {
public static void main(String[] args){
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(9999);
System.out.println("等待连接.......");
Socket socket;
socket = serverSocket.accept(); //一直阻塞
System.out.println("客户端已连接!");
InputStream ins = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(ins,"utf-8");
BufferedReader bReader = new BufferedReader(isr);
String line = "";
StringBuffer buffer = new StringBuffer();
while(!("==END==").equals(line=bReader.readLine())){
System.out.println("客户端:"+line);
buffer.append(line+"\n");
}
System.out.println("接收到的完整buffer:"+buffer.toString());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
String str = new String(buffer);
oos.writeObject(str);
byte [] strData = baos.toByteArray();
ByteArrayInputStream baoi = new ByteArrayInputStream(strData);
ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(baoi));
try {
Object Obj = ois.readObject();
System.out.println(Obj.getClass());
System.out.println("对象反序列化成功!");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
finally {
serverSocket.close();
socket.close();
ins.close();
isr.close();
baos.close();
baoi.close();
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Python客户端demo
#!/usr/bin/env Python3
# -*- encoding:utf-8 -*-
import socket,pickle
class Employee:
def __init__(self,name,sex,age,salary):
self.name = name #姓名
self.sex = sex #性别
self.__age = age #年龄 私有变量
self.salary= salary #薪资 按月算
@property
def age(self): #age的getter属性,还记得装饰器@property的用法吗?
return self.__age
@age.setter
def age(self,value): #age的setter属性
self.__age = value
def add(self,a,b):
return a+b
person = Employee('张三','男',35,6000.00)
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('127.0.0.1',9999))
s.send(pickle.dumps(person)+bytes('\n==END==\n',encoding='utf-8'))
运行客户端,由于客户端没有接收部分,所以,我们直接看Java服务端
为了使Java服务端正常的运作,耍了一下小聪明,我们用Python传过来的字节流初始化了一个String对象str,因为谁也没告诉我,Python传过来的字节流里面装的究竟是啥(一堆乱码,我Java一脸懵逼),我就假设一下是字符串对象,显然,字符串对象序列化后,在反序列化后仍然是字符串,也就是Python传过来的内容,我Java这边只能胡乱猜测,猜测的结果就是又绕回去了。这就牵扯到了不同语言之间的序列化共性问题了,也就是你Python序列化后的字节流,你自己清楚该怎么反序列回去,而我Java则是按照自己的序列化规则走,因此,就导致,双方无法通过序列化后的字节流进行交流。
我们看下,Python是不是可以识别这些"乱码"
在Python中用pickle.load反序列1.txt里面的内容,还原对象如下
这就让人不淡定了,那我怎么让Python的对象序列化后的内容分享给Java,让Java也能看到呢?
记住,不管你是哪种编程语言,你肯定能识别字符串对吧,基本数据类型啊,连这都识别不了,你想干嘛,是不是想上上天啊?
好了,既然是字符串,结合上一篇所讲,在Python中,我们引入json模块,使用dumps函数将对象序列化成json串,然后,我们拿这个json串再交给Java,Java不就能识别了嘛,而且,Java还能对json串进行详细的解析,不信吗?不信,我们就来看一下demo案列:
服务端依然由Java来接收(Java需要引入相关的Jar包,这里是讲Python,Java不是重点):
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class ServerTest {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("等待连接.......");
Socket socket = serverSocket.accept();//一直阻塞
System.out.println("客户端已连接!");
//如果连上了 执行下面的语句
//读取输入流 看看客户端说了什么
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is,"GBK");
BufferedReader bReader = new BufferedReader(isr);
String line = "";
while(!"==END==".equals(line =bReader.readLine())){
System.out.println("客户端:"+line);
JsonParser parser=new JsonParser(); //创建JSON解析器
JsonObject object=(JsonObject) parser.parse(line); //创建JsonObject对象
JsonArray array=object.get("data").getAsJsonArray(); //得到为json的数组
for(int i=0;i<array.size();i++){
System.out.println("---------------");
JsonObject subObject=array.get(i).getAsJsonObject();
System.out.println("name="+subObject.get("name").getAsString());
System.out.println("sex="+subObject.get("sex").getAsString());
// System.out.println("age"+subObject.get("_Employee__age").getAsString());
System.out.println("age="+subObject.get("age").getAsString());
System.out.println("sum="+subObject.get("sum").getAsInt());
}
}
socket.shutdownInput();//关闭输入流
//响应连接用户信息
OutputStream os = socket.getOutputStream();
PrintWriter writer = new PrintWriter(os);
writer.write("服务端: "+socket.getInetAddress().toString().replaceAll("/", "")+",您好!你传过来的JSON数据,我已成功接收并解析。");
writer.flush();
writer.close();
os.close();
bReader.close();
isr.close();
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
启动服务端
客户端由我们的Python来处理数据(demo和上一篇如出一辙,就不细说了)
#!/usr/bin/env Python3
# -*- encoding:utf-8 -*-
import socket,pickle,json
class Employee:
def __init__(self,name,sex,age,salary):
self.name = name #姓名
self.sex = sex #性别
self.__age = age #年龄 私有变量
self.salary= salary #薪资 按月算
@property
def age(self): #age的getter属性,还记得装饰器@property的用法吗?
return self.__age
@age.setter
def age(self,value): #age的setter属性
self.__age = value
def add(self,a,b):
return a+b
p1 = Employee('张三','男',35,6000.00)
#动态绑定实例的属性变量
p1.a = 4
p1.b = 5
p2 = Employee('李婷','女',25,4000.00)
p2.a = 10
p2.b = 20
p3 = Employee('王五','男',30,5000.00)
p3.a = 11
p3.b = 25
L=[]
L.append(p1)
L.append(p2)
L.append(p3)
def ToJson(obj):
return {
'name' :obj.name,
'sex' :obj.sex ,
'age' :obj.age ,
'salary':obj.salary,
'sum' :obj.add(obj.a,obj.b)
}
data = json.dumps(L,default=ToJson)
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('192.168.1.54',9999))
#s.send(bytes(data,encoding='utf-8'))
data = '{ "data":'+data+'}'
s.send(bytes(data+'\n==END==\n',encoding='utf-8'))
buff = []
while True:
b = s.recv(1024)
if b:
buff.append(b)
else:
break;
for msg in buff:
#print(msg.decode('utf-8'))
print(msg.decode('gb2312'))
s.close()
运行客户端,走你(不要注重demo,主要看效果)
服务端
Java处理完Python发过来的json数据之后,会告诉Python,兄弟,谢谢你啊,数据我收到了!当然,这是我说的。
客户端
本篇是对上一篇的承诺,如果我们只知道Python有个序列化和反序列化,而不知道怎么用的话,或者,我们就是自己跟自己玩,这种情况,完全不必担心反序列化会出问题,照着函数用就行;万一,让你和其他语言一起玩,你是不是就愣住了,这时候,不要怕,只要你会用Python的json模块,你就可以跟其他语言掰掰手腕了:"你要数据是吧,没问题,扔给你一个json字符串,自己玩去吧!",