最近因为项目需求,要求能在python和java之间传输数据,所以了解了一下socket,通过使用socket在两种语言之间传输数据。期间遇见了不少坑,记录一下,算是给后来人一个借鉴(说起来都是泪啊 。。。。。)
1. 先说一下我要干什么,我通过base64编码将图片从前端传到了服务器(java写的网站),然后需要把图片数据传输到python中实现一些功能。其中使用python作为服务端,java作为客户端。服务端(python)
使用python的socket模块写客户端的时候到时没什么大问题。按照基本步骤来就行了(就当读者已经了解socket的大致运作方式,下面给出代码实现,有注释…)
import socket
# 在构建socket的时候需要用到ip和端口,必须是元组的形式。
# 另外,因为是本机上的两个程序通信,所以设置成localhost,
# 如果要和网络上的其他主机进行通信,则填上相应主机的ip地
# 址,端口的话随便设置一个,不要和已知的一些服务冲突就行
adress = ('localhost', 9999)
# 创建socket对象,同时设置通信模式,AF_INET代表IPv4,SOCK_STREAM代表流式socket,使用的是tcp协议
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定到我们刚刚设置的ip和端口元组,代表我们的服务运行在本机的9999端口上
server.bind(address)
# 开始监听,5位最大挂起的连接数
server.listen(5)
# 无限循环,实现反复接收请求
while True:
# accept()方法被动接受客户端连接,阻塞,等待连接. client是客户端的socket对象,可以实现消息的接收和发送,addr表示客户端的地址
client, addr = server.accept()
data = client.recv(13) # 代表从发过来的数据中读取13byte的数据
data1 = client.recv(4) # 再接收4byte数据
client.sendall(b'1') # 发送消息给客户端,发送的消息必须是byte类型
client.close() # 关闭连接
server.close()
呼,终于写完了,感觉注释应该很详细了吧。
我必须要再说一点很重要的东西:服务端每次接受的数据是有限制的,也就是说文件大一点的话你要分好多次接收,比如我要传输图片的话只接收一次是根本接收不全的,每次收到的数据都少很多。一定要注意!一定要注意!一定要注意!
附上我的解决代码(献丑了 ? )
img_base64 = b''
max_size = 1024 # 设置每次接收1024byte,当然也可以更大,只要不超过缓冲区大小就行
sum = img_length # img_length是我的图片数据的长度
while sum >= max_size: # 每次接收1024,直到剩下的数据小于1024
img_base64 = img_base64 + conn.recv(max_size)
sum -= max_size
if sum != 0: # 如果还剩下数据的话就接收完
mg_base64 = img_base64 + conn.recv(sum)
python服务端的代码就到此为止了。。
但是 ! ! !, 我还有问题要说,我原来是想传过来base64编码的图片数据,然后用python解码然后转换成图片,但是没搞成功,不是出现Incorrect padding异常就是解码后的数据不能正常使用,着实是没搞懂(黑人问号脸???)是python的base64太垃圾了?还是我太垃圾了?(沮丧。。)
然后把解码base64图片的工作放在了java中就行了。。。
客户端(java)
用java做客户端还是很好写的,网上的资源也是很全的,直接上代码了:
我把通信过程都放在了一个函数里面,传入的参数是两个byte[]类型的数据,这是我的项目要求,对于读者来说也可以传入一个或多个都行
// 传递信息
public String sendMessage(byte[] header, byte[] data) {
String ip = "localhost"; // 设置发送地址和端口号
int port = 9999;
Socket socket = null;
try {
// 连接服务器
socket = new Socket(ip, port);
// 获取输入流
InputStream in = socket.getInputStream(); //读取数据
// 获取输出流
OutputStream out = socket.getOutputStream(); // 发送数据
// 包装输入流,输出流,包装一下可以直接传输字符串,不包装的话直接使用InputStream和OutputStream只能直接传输byte[]类型数据
BufferedReader inRead = new BufferedReader(new InputStreamReader(in));
// PrintWriter outWriter = new PrintWriter(out);
// 发送数据
out.write(header);
out.write(data);
// 接受应答
String result = inRead.readLine(); // 使用了包装后的输入流方便读取消息
return result;
} catch(UnknownHostException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
return "defeat";
}