protobuf 怎么在iOS中实用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了protobuf 怎么在iOS中实用相关的知识,希望对你有一定的参考价值。

有两种方式,一是直接使用C++版, 引用.h和dylib就可以了, 用在64位的5s上很容易,但是在5以下的32位上编译环不容易弄对。
二是用objc版的。可以参考如下操作:
1,下载ProtocolBuffer包,并按照包中根目录下README.txt安装。
make install后,会生成编译器protoc,并拷贝到/usr/local/bin目录下。

2,下载Objective-C compiler for ProtocolBuffer。

目前有两种类型的实现。

一个针对ProtocolBuffer2.2做修改,使最后生成的.proto文件编译器(protoc)支持Objective-C类型的文件输出。

它在这里:http://code.google.com/p/metasyntactic/wiki/ProtocolBuffers

另一个针对ProtocolBuffer2.3推出的plugin模式编写插件,以插件方式支持Objective-C类型的文件输出。

它在这里:https://github.com/booyah/protobuf-objc

我选用第二种方式,这也是Google推荐的方式。

git clone https://github.com/booyah/protobuf-objc.git

默认会在当前运行目录下创建protobuf-objc目录。进入该目录,并执行:

./autogen.sh

./configure

make

make install

最终生成的插件名字为protoc-gen-objc,会被安装到/usr/local/bin/目录下。

3,测试.proto文件编译。

随便写一个test.proto文件,并编译该文件。命令是:

protoc –objc_out=/Output/Directory/ test.proto

protoc会自动在/usr/local/bin/目录下寻找名为”protoc-gen-objc”的插件,并使用该插件编译.proto文件,最终生成两个文件:

test.pb.h

test.pb.m

这个步骤通过后,说明ProtocoBuffer Compiler for Objective-C可以正常工作了。

4,在Xcode4.3.1中使用ProtocolBuffer

将步骤2中protobuf-obj/src/runtime/Classes目录导入到Xcode项目中,导入时,选中”Copy items into destination group‘s folder(if needed)“。

导入位置选择项目根目录。导入完毕后,项目根目录下将会出现Classes目录。将该目录改名为ProtocolBuffers(注意最后的s):

mv Classes ProtocolBuffers

修改项目属性中”Build Setting——>Header Search Pathes”,将项目根目录“.”添加到头文件搜索路径中去。

这样ProtocolBuffer for Objective-C的工作环境就配置好了。

5,使用

将步骤3中编译输出的test.pb.h和test.pb.m添加到项目中,就可以直接使用了。
参考技术A 一、Protobuf的使用
首先来简单介绍一下Protobuf的使用,这里以windows下java开发为例,几个步骤:编写*.proto ->使用google提供的protoc.exe生成*.java->项目中导入protobuf的.jar包进行开发即可。先看这里的*.proto文件:

[plain] view plain copy
package com;

message CMsg

required string msghead = 1;
required string msgbody = 2;


message CMsgHead

required int32 msglen = 1;
required int32 msgtype = 2;
required int32 msgseq = 3;
required int32 termversion = 4;
required int32 msgres = 5;
required string termid = 6;


message CMsgReg

optional int32 area = 1;
optional int32 region = 2;
optional int32 shop = 3;
optional int32 ret = 4;
optional string termid = 5;


使用protoc.exe生成java文件,命令如下:

将生成的Msg.java及protobuf-java-2.3.0.jar导入项目中进行开发,这里写一个服务器端ProtobufServer及客户端ProtobufClient

[java] view plain copy
package com;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

import com.Msg.CMsg;
import com.Msg.CMsgHead;
import com.Msg.CMsgReg;

public class ProtoServer implements Runnable

@Override
public void run()
try
System.out.println("beign:");
ServerSocket serverSocket = new ServerSocket(12345);
while (true)
System.out.println("等待接收用户连接:");
// 接受客户端请求
Socket client = serverSocket.accept();

DataOutputStream dataOutputStream;
DataInputStream dataInputStream;

try
InputStream inputstream = client.getInputStream();
dataOutputStream = new DataOutputStream(
client.getOutputStream());

byte len[] = new byte[1024];
int count = inputstream.read(len);
byte[] temp = new byte[count];
for (int i = 0; i < count; i++)
temp[i] = len[i];


CMsg msg = CMsg.parseFrom(temp);

CMsgHead head = CMsgHead.parseFrom(msg.getMsghead()
.getBytes());
System.out.println("==len===" + head.getMsglen());
System.out.println("==res===" + head.getMsgres());
System.out.println("==seq===" + head.getMsgseq());
System.out.println("==type===" + head.getMsgtype());
System.out.println("==Termid===" + head.getTermid());
System.out.println("==Termversion==="
+ head.getTermversion());

CMsgReg body = CMsgReg.parseFrom(msg.getMsgbody()
.getBytes());
System.out.println("==area==" + body.getArea());
System.out.println("==Region==" + body.getRegion());
System.out.println("==shop==" + body.getShop());

sendProtoBufBack(dataOutputStream);
inputstream.close();

catch (Exception ex)
System.out.println(ex.getMessage());
ex.printStackTrace();
finally
client.close();
System.out.println("close");



catch (IOException e)
System.out.println(e.getMessage());



private byte[] getProtoBufBack()

// head
CMsgHead head = CMsgHead.newBuilder().setMsglen(10).setMsgtype(21)
.setMsgseq(32).setTermversion(43).setMsgres(54)
.setTermid("Server:head").build();

// body
CMsgReg body = CMsgReg.newBuilder().setArea(11).setRegion(22)
.setShop(33).setRet(44).setTermid("Server:body").build();

// Msg
CMsg msg = CMsg.newBuilder()
.setMsghead(head.toByteString().toStringUtf8())
.setMsgbody(body.toByteString().toStringUtf8()).build();

return msg.toByteArray();


private void sendProtoBufBack(DataOutputStream dataOutputStream)

byte[] backBytes = getProtoBufBack();

// Integer len2 = backBytes.length;

// byte[] cmdHead2 = BytesUtil.IntToBytes4(len2);

try
// dataOutputStream.write(cmdHead2, 0, cmdHead2.length);
dataOutputStream.write(backBytes, 0, backBytes.length);
dataOutputStream.flush();
catch (IOException e)
e.printStackTrace();



public static void main(String[] args)
Thread desktopServerThread = new Thread(new ProtoServer());
desktopServerThread.start();




[java] view plain copy
package com;

import java.io.InputStream;
import java.net.Socket;

import com.Msg.CMsg;
import com.Msg.CMsgHead;
import com.Msg.CMsgReg;

public class ProtoClient

public static void main(String[] args)
ProtoClient pc=new ProtoClient();
System.out.println("beign:");
pc.runget();


public void runget()
Socket socket = null;
try
//socket = new Socket("localhost", 12345);
socket = new Socket("192.168.85.152", 12345);
// head
CMsgHead head = CMsgHead.newBuilder().setMsglen(5).setMsgtype(1)
.setMsgseq(3).setTermversion(41).setMsgres(5)
.setTermid("Client:head").build();

// body
CMsgReg body = CMsgReg.newBuilder().setArea(11).setRegion(22)
.setShop(33).setRet(44).setTermid("Clent:body").build();

// Msg
CMsg msg = CMsg.newBuilder()
.setMsghead(head.toByteString().toStringUtf8())
.setMsgbody(body.toByteString().toStringUtf8()).build();

// 向服务器发送信息
System.out.println("sendMsg...");
msg.writeTo(socket.getOutputStream());

// 接受服务器的信息
InputStream input = socket.getInputStream();

System.out.println("recvMsg:");
byte[] by = recvMsg(input);
printMsg(CMsg.parseFrom(by));

input.close();
socket.close();
catch (Exception e)
System.out.println(e.toString());



public void printMsg(CMsg g)

try
CMsgHead h = CMsgHead.parseFrom(g.getMsghead().getBytes());
StringBuffer sb = new StringBuffer();
if (h.hasMsglen())
sb.append("==msglen===" + h.getMsglen() + "\n");
if (h.hasMsgres())
sb.append("==msgres===" + h.getMsgres() + "\n");
if (h.hasMsgseq())
sb.append("==msgseq===" + h.getMsgseq() + "\n");
if (h.hasMsgtype())
sb.append("==msgtype===" + h.getMsgtype() + "\n");
if (h.hasTermid())
sb.append("==termid===" + h.getTermid() + "\n");
if (h.hasTermversion())
sb.append("==termversion===" + h.getTermversion() + "\n");

CMsgReg bo = CMsgReg.parseFrom(g.getMsgbody().getBytes());
if (bo.hasArea())
sb.append("==area==" + bo.getArea() + "\n");
if (bo.hasRegion())
sb.append("==region==" + bo.getRegion() + "\n");
if (bo.hasShop())
sb.append("==shop==" + bo.getShop() + "\n");
if (bo.hasRet())
sb.append("==ret==" + bo.getRet() + "\n");
if (bo.hasTermid())
sb.append("==termid==" + bo.getTermid() + "\n");

System.out.println(sb.toString());

catch (Exception e)
e.printStackTrace();




public byte[] recvMsg(InputStream inpustream)
byte[] temp = null;
try

byte len[] = new byte[1024];
int count = inpustream.read(len);

temp = new byte[count];
for (int i = 0; i < count; i++)
temp[i] = len[i];

return temp;
catch (Exception e)
System.out.println(e.toString());
return temp;


本回答被提问者采纳

如何在 iOS 中链接 protobuf

【中文标题】如何在 iOS 中链接 protobuf【英文标题】:How to link protobufs in iOS 【发布时间】:2018-01-20 11:40:37 【问题描述】:

我一直在努力让 protobufs 3 为 iOS 编译/运行。一切都编译,但在运行时我得到:

dyld: Library not loaded: /usr/local/lib/libprotobuf.15.dylib
Referenced from: /path/to/TheApp.app/TheApp
Reason: no suitable image found.  Did find: 
    /usr/local/lib/libprotobuf.15.dylib: mach-o, but not built for iOS simulator

这是我的步骤:

    使用this excellent script为所有架构编译静态库。 将静态库添加到编译目标的General 选项卡下的Linked Frameworks and Libraries 部分。 构建 => 成功

【问题讨论】:

【参考方案1】:

首先,我认为构建脚本实际上并不是在构建静态库。我浏览了脚本并使用lipootool 等工具检查了构建输出。看起来正确。

然后我在构建输出中遇到了这个警告:

URGENT: building for iOS simulator, but linking against dylib (/usr/local/lib/libprotobuf.dylib) built for OSX

我仔细检查了构建目标,以确保我的目标是 iOS。好的。

然后我开始寻找为什么它会链接到动态库,即使一切都是静态的,并在互联网上看到一篇文章说 OSX 更喜欢链接到 DLL 而不是静态库。如果你想解决这个问题,你必须设置你的构建命令some kind of style。我在 Xcode 编辑器中,所以我没有做翻译这个练习。

但是,鉴于此,我删除了对动态库的引用,以查看回退到静态:

rm /usr/local/lib/libprotobuf.dylib

构建。跑。成功。

所以原因是已知的,但这个答案是不完整的。请编辑此答案并提供有关如何让 Xcode 强制静态链接与获取 dylib 的详细信息,以及仅删除 dylib 参考的详细信息

【讨论】:

以上是关于protobuf 怎么在iOS中实用的主要内容,如果未能解决你的问题,请参考以下文章

Jmeter protobuf 测试。无法读取 Protobuf 消息

尴尬的事情又发生Newtonsoft.Json vs Protobuf.net

尴尬的事情又发生Newtonsoft.Json vs Protobuf.net

服务器更改时如何为客户端更新 protobuf 文件

Unity安装配置Python使用protobuf转换Excel表格数据并在unit中使用

Unity安装配置Python使用protobuf转换Excel表格数据并在unit中使用