是这样的,我们有个棋牌项目是 lua 的,网络通信这块用的原生 Socket。现在有个新的换皮换玩法项目,我打算用 Creator 重构。而服务器暂时还是 Socket。所以我打算通过 JSB 把原来项目的C++ 的 Socket 暴露给 JS 层。这样的话以后如果服务器换 socket.io 的话,我就重写一下 Socket 这块就能发 H5 了。
问题
-
这样的话会不会有什么我考虑不到的问题
-
我按照官网文档操作,用 VS Windows下调试,JS 成功调用了 C++ 的 Socket 方法,而在 C++ 调用 JS 回调的时候出现了异常。搞不懂是怎么回事,代码如下
/*
* SKSocket.cpp
*/
...
void SK::SKSocket::connect(const char* server, int port, const std::function<void(const string&)>& cb)
{
_serverAddress = Socket::getIpAddress(server);
_socketLogic->openWithIp(_serverAddress.c_str(), port, true);
_connectCB = cb;
}
void SK::SKSocket::onConnected()
{
CCLOG("联网成功");
_connected = true;
if (_connectCB != nullptr)
{
_connectCB("OK");
}
}
...
static bool js_SKSocket_connect(se::State& s)
{
const auto& args = s.args();
int argc = (int)args.size();
if (argc >= 2)
{
SK::SKSocket* cobj = (SK::SKSocket*)s.nativeThisObject();
se::Value jsServerAddress = args[0];
se::Value jsServerPort = args[1];
se::Value jsFunc = argc > 2 ? args[2] : se::Value::Undefined;
se::Value jsTarget = argc > 3 ? args[3] : se::Value::Undefined;
if (jsFunc.isNullOrUndefined())
{
cobj->connect(jsServerAddress.toString().c_str(), jsServerPort.toInt32(), nullptr);
}
else
{
assert(jsFunc.isObject() && jsFunc.toObject()->isFunction());
// 如果当前 SomeClass 是可以被 new 出来的类,我们 使用 se::Object::attachObject 把 jsFunc 和 jsTarget 关联到当前对象中
//s.thisObject()->attachObject(jsFunc.toObject());
//s.thisObject()->attachObject(jsTarget.toObject());
// 如果当前 SomeClass 类是一个单例类,或者永远只有一个实例的类,我们不能用 se::Object::attachObject 去关联
// 必须使用 se::Object::root,开发者无需关系 unroot,unroot 的操作会随着 lambda 的销毁触发 jsFunc 的析构,在 se::Object 的析构函数中进行 unroot 操作。
// js_cocos2dx_EventDispatcher_addCustomEventListener 的绑定代码就是使用此方式,因为 EventDispatcher 始终只有一个实例,
// 如果使用 s.thisObject->attachObject(jsFunc.toObject);会导致对应的 func 和 target 永远无法被释放,引发内存泄露。
jsFunc.toObject()->root();
if (jsTarget.isObject())
{
jsTarget.toObject()->root();
}
cobj->connect(jsServerAddress.toString().c_str(), jsServerPort.toInt32(), [jsFunc, jsTarget](const string& counter) {
// CPP 回调函数中要传递数据给 JS 或者调用 JS 函数,在回调函数开始需要添加如下两行代码。
se::ScriptEngine::getInstance()->clearException();
se::AutoHandleScope hs; //** 这里出现异常* *
se::ValueArray args;
args.push_back(se::Value(counter));
se::Object* target = jsTarget.isObject() ? jsTarget.toObject() : nullptr;
jsFunc.toObject()->call(args, target);
});
}
return true;
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", argc, 2);
return false;
}
SE_BIND_FUNC(js_SKSocket_connect)
...
/*
* HelloJsb.ts
*/
...
onLoad() {
cc.log("HelloJsb onLoad");
new SK.SKSocket().connect("x.x.x.x", 8888, ()=>{
cc.log("JSSocket.connect success");
});
}
...
这里出现异常:
se::AutoHandleScope hs;
异常信息:
0x03B6794B (v8.dll)处(位于 jsb2test.exe 中)引发的异常: 0xC0000005: 读取位置 0x00000E48 时发生访问冲突。 出现了
