mirror of
https://github.com/u0u0/Cocos2d-Lua-Community.git
synced 2026-06-09 16:07:51 +08:00
重造了一个异步tcp的轮子。
This commit is contained in:
364
cocos/network/AsyncTCP.cpp
Normal file
364
cocos/network/AsyncTCP.cpp
Normal file
@@ -0,0 +1,364 @@
|
||||
// Copyright 2020 KeNan Liu
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <functional>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef _WIN32
|
||||
#include <WinSock2.h> // struct sockaddr_in
|
||||
#include <WS2tcpip.h>
|
||||
#pragma comment(lib,"WS2_32.lib")
|
||||
#else
|
||||
#include <arpa/inet.h> // struct sockaddr_in
|
||||
#include <netdb.h> // addrinfo
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#endif // !_WIN32
|
||||
|
||||
#include "cocos/network/AsyncTCP.h"
|
||||
#include "base/CCScheduler.h"
|
||||
#include "base/CCDirector.h"
|
||||
|
||||
static int checkIPv6(const char *hostname, bool &isIpv6)
|
||||
{
|
||||
struct addrinfo *iterator = NULL, *resolved = NULL;
|
||||
struct addrinfo hints;
|
||||
int ret = 0;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
|
||||
ret = getaddrinfo(hostname, NULL, &hints, &resolved);
|
||||
if (ret != 0) {
|
||||
printf("== AsyncTCP getaddrinfo error:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
isIpv6 = false;
|
||||
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
||||
char hbuf[NI_MAXHOST];
|
||||
ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen,
|
||||
hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
|
||||
if (ret) {
|
||||
freeaddrinfo(resolved);
|
||||
printf("== AsyncTCP getnameinfo error:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (iterator->ai_family == AF_INET6) {
|
||||
isIpv6 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeaddrinfo(resolved);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AsyncTCP::initEnv()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
auto ver = WSAStartup(MAKEWORD(2, 0), &wsaData);
|
||||
if (ver) {
|
||||
printf("WSAStartup failed !\n");
|
||||
}
|
||||
#else
|
||||
signal(SIGPIPE, SIG_IGN);// avoid crash when socket is closed
|
||||
#endif
|
||||
}
|
||||
|
||||
AsyncTCP::AsyncTCP()
|
||||
:_tcp(-1)
|
||||
,_host("")
|
||||
,_port(0)
|
||||
,_cb(nullptr)
|
||||
,_quit(false)
|
||||
,_thread(nullptr)
|
||||
{
|
||||
cocos2d::Director::getInstance()->getScheduler()->schedule(CC_SCHEDULE_SELECTOR(AsyncTCP::update), this, 0, false);
|
||||
}
|
||||
|
||||
AsyncTCP::~AsyncTCP()
|
||||
{
|
||||
close();
|
||||
waitThreadAndClean();
|
||||
cocos2d::Director::getInstance()->getScheduler()->unschedule(CC_SCHEDULE_SELECTOR(AsyncTCP::update), this);
|
||||
}
|
||||
|
||||
void AsyncTCP::setEventCB(std::function<void(int state, unsigned char *msg, size_t size)> cb)
|
||||
{
|
||||
_cb = cb;
|
||||
}
|
||||
|
||||
void AsyncTCP::open(const std::string host, int port)
|
||||
{
|
||||
// lua must call close() first, wait CLOSED event, then can open again.
|
||||
waitThreadAndClean();
|
||||
|
||||
_quit = false;
|
||||
_host = host;
|
||||
_port = port;
|
||||
_thread = new std::thread(&AsyncTCP::socketThread, this);
|
||||
}
|
||||
|
||||
void AsyncTCP::send(unsigned char *buffer, size_t len)
|
||||
{
|
||||
if (_tcp < 0) {
|
||||
printf("==send Error, AsyncTCP NOT opened\n");
|
||||
return;
|
||||
}
|
||||
|
||||
TCPData *data = new TCPData(0, buffer, len);
|
||||
sendMutex.lock();
|
||||
sendQueue.push(data);
|
||||
sendMutex.unlock();
|
||||
}
|
||||
|
||||
void AsyncTCP::close()
|
||||
{
|
||||
_quit = true;// make socketThread exit
|
||||
}
|
||||
|
||||
void AsyncTCP::notify(int state, unsigned char *msg, size_t size)
|
||||
{
|
||||
TCPData *data = new TCPData(state, msg, size);
|
||||
getMutex.lock();
|
||||
getQueue.push(data);
|
||||
getMutex.unlock();
|
||||
}
|
||||
|
||||
void AsyncTCP::waitThreadAndClean()
|
||||
{
|
||||
if (_thread) {
|
||||
_thread->join();
|
||||
delete _thread;
|
||||
}
|
||||
// clean cache
|
||||
while (!sendQueue.empty()) {
|
||||
TCPData *data = sendQueue.front();
|
||||
sendQueue.pop();
|
||||
delete data;
|
||||
}
|
||||
while (!getQueue.empty()) {
|
||||
TCPData *data = getQueue.front();
|
||||
getQueue.pop();
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncTCP::update(float dt)
|
||||
{
|
||||
while (true) {
|
||||
// get data from queue
|
||||
TCPData *data = nullptr;
|
||||
getMutex.lock();
|
||||
if (!getQueue.empty()) {
|
||||
data = getQueue.front();
|
||||
getQueue.pop();
|
||||
}
|
||||
getMutex.unlock();
|
||||
// not data, break
|
||||
if (!data) break;
|
||||
// notify lua
|
||||
_cb(data->state, data->buffer, data->size);
|
||||
// free data
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncTCP::socketThread()
|
||||
{
|
||||
// 1. check dns isIpv6
|
||||
notify(EVENT_CONNECTING, nullptr, 0);
|
||||
bool isIpv6;
|
||||
if (checkIPv6(_host.c_str(), isIpv6)) {
|
||||
notify(EVENT_FAILED, nullptr, 0);
|
||||
return; // get error in checkIPv6
|
||||
}
|
||||
|
||||
// 2. open socket
|
||||
if (openTCP(isIpv6) < 0) {
|
||||
closeTCP();
|
||||
notify(EVENT_FAILED, nullptr, 0);
|
||||
return; // open error
|
||||
}
|
||||
notify(EVENT_CONNECTED, nullptr, 0);
|
||||
|
||||
// 3. TCP loop
|
||||
while (true) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));// 1 ms
|
||||
if (_quit) break;
|
||||
|
||||
if (recvTCP() < 0) break;
|
||||
|
||||
int rtn;
|
||||
while (true) {
|
||||
// get data from queue
|
||||
TCPData *data = nullptr;
|
||||
rtn = 0;
|
||||
sendMutex.lock();
|
||||
if (!sendQueue.empty()) {
|
||||
data = sendQueue.front();
|
||||
sendQueue.pop();
|
||||
}
|
||||
sendMutex.unlock();
|
||||
// not data, break
|
||||
if (!data) break;
|
||||
// send data
|
||||
rtn = sendTCP(data->buffer, data->size);
|
||||
// free data
|
||||
delete data;
|
||||
// closed
|
||||
if (rtn < 0) break;
|
||||
}
|
||||
if (rtn < 0) break; // closed
|
||||
}
|
||||
|
||||
// 4. close
|
||||
closeTCP();
|
||||
notify(EVENT_CLOSED, nullptr, 0);
|
||||
}
|
||||
|
||||
int AsyncTCP::recvTCP()
|
||||
{
|
||||
unsigned char rbuf[1024] = {0};
|
||||
while (true) {
|
||||
int ret = recv(_tcp, rbuf, sizeof(rbuf), 0);
|
||||
int err = errno;
|
||||
if (ret > 0) {
|
||||
notify(EVENT_DATA, rbuf, ret);
|
||||
continue;
|
||||
}
|
||||
if (ret == 0) {
|
||||
return -1; // closed
|
||||
}
|
||||
|
||||
if (err == EINTR) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));// 1 ms
|
||||
continue; // Interrupted
|
||||
}
|
||||
if (err == EAGAIN) {
|
||||
break; // block, no more data
|
||||
}
|
||||
// other error
|
||||
return -1; // closed
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AsyncTCP::sendTCP(unsigned char *buff, size_t size)
|
||||
{
|
||||
size_t offset = 0;
|
||||
while (true) {
|
||||
int ret = ::send(_tcp, buff + offset, size, 0);
|
||||
int err = errno;
|
||||
if (ret >= 0) {
|
||||
size -= ret;
|
||||
if (size == 0) break; // all sended
|
||||
offset += ret;
|
||||
continue;
|
||||
}
|
||||
// Interrupted or block
|
||||
if (err == EINTR || err == EAGAIN) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));// 1 ms
|
||||
continue;
|
||||
}
|
||||
// other error
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AsyncTCP::openTCP(bool isIpv6)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (isIpv6) {
|
||||
_tcp = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
|
||||
} else {
|
||||
_tcp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
}
|
||||
if (_tcp < 0) {
|
||||
printf("==socket error with errno: %d, %s\n", errno, strerror(errno));
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (isIpv6) {
|
||||
struct sockaddr_in6 servaddr6;
|
||||
memset(&servaddr6, 0, sizeof(servaddr6));
|
||||
servaddr6.sin6_family = AF_INET6;
|
||||
servaddr6.sin6_port = htons(_port);
|
||||
ret = inet_pton(AF_INET6, _host.c_str(), &servaddr6.sin6_addr);
|
||||
if (ret <= 0) {
|
||||
printf("==inet_pton AF_INET6 ret %d, errno %d, %s\n", ret, errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
ret = connect(_tcp, (const struct sockaddr*)(&servaddr6), sizeof(servaddr6));
|
||||
if (ret < 0) {
|
||||
printf("==connect6 error with errno: %d, %s\n", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
struct sockaddr_in servaddr;
|
||||
memset(&servaddr, 0, sizeof(servaddr));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_port = htons(_port);
|
||||
ret = inet_pton(AF_INET, _host.c_str(), &servaddr.sin_addr);
|
||||
if (ret <= 0) {
|
||||
printf("==inet_pton AF_INET ret %d, errno %d, %s\n", ret, errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
ret = connect(_tcp, (const struct sockaddr*)(&servaddr), sizeof(servaddr));
|
||||
if (ret < 0) {
|
||||
printf("==connect error with errno: %d, %s\n", errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// set non-blocking after connected.
|
||||
#ifdef _WIN32
|
||||
unsigned long NoBlock = 1UL;
|
||||
int nRes = ioctlsocket(_tcp, FIONBIO, &NoBlock);
|
||||
if (nRes == SOCKET_ERROR) {
|
||||
printf("==ioctlsocket error with errno: %d, %s\n", errno, strerror(errno));
|
||||
return -3;
|
||||
}
|
||||
#else
|
||||
int flags = fcntl(_tcp, F_GETFL, 0);
|
||||
if (flags == -1) {
|
||||
printf("==socket non-blocking get fcntl error with errno: %d, %s\n", errno, strerror(errno));
|
||||
return -3;
|
||||
}
|
||||
ret = fcntl(_tcp, F_SETFL, flags | O_NONBLOCK);
|
||||
if (ret == -1) {
|
||||
printf("==socket non-blocking set fcntl error with errno: %d, %s\n", errno, strerror(errno));
|
||||
return -3;
|
||||
}
|
||||
#endif //!WIN32
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AsyncTCP::closeTCP()
|
||||
{
|
||||
if (_tcp > 0) {
|
||||
#if _WIN32
|
||||
closesocket(_tcp);
|
||||
#else
|
||||
::close(_tcp);
|
||||
#endif
|
||||
_tcp = -1;
|
||||
}
|
||||
}
|
||||
91
cocos/network/AsyncTCP.h
Normal file
91
cocos/network/AsyncTCP.h
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright 2020 KeNan Liu
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __ASYNC_TCP_H__
|
||||
#define __ASYNC_TCP_H__
|
||||
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include "base/CCRef.h"
|
||||
|
||||
class AsyncTCP : public cocos2d::Ref
|
||||
{
|
||||
public:
|
||||
static void initEnv();
|
||||
AsyncTCP();
|
||||
~AsyncTCP();
|
||||
|
||||
// state: 1 connecting, 2 failed, 3 connected, 4 data, 5 closed.
|
||||
void setEventCB(std::function<void(int state, unsigned char *msg, size_t size)> cb);
|
||||
void open(const std::string host, int port);
|
||||
void send(unsigned char *buffer, size_t len);
|
||||
void close();
|
||||
|
||||
private:
|
||||
enum {
|
||||
EVENT_CONNECTING,
|
||||
EVENT_FAILED,
|
||||
EVENT_CONNECTED,
|
||||
EVENT_CLOSED,
|
||||
EVENT_DATA
|
||||
};
|
||||
|
||||
struct TCPData {
|
||||
public:
|
||||
TCPData(int stat, unsigned char *b, size_t s)
|
||||
: buffer(nullptr)
|
||||
, size(s)
|
||||
, state(stat)
|
||||
{
|
||||
buffer = (unsigned char *)malloc(s);
|
||||
memcpy(buffer, b, s);
|
||||
}
|
||||
~TCPData()
|
||||
{
|
||||
if (buffer) free(buffer);
|
||||
};
|
||||
unsigned char *buffer;
|
||||
size_t size;
|
||||
int state;
|
||||
};
|
||||
|
||||
void update(float dt);
|
||||
void waitThreadAndClean();
|
||||
|
||||
void socketThread();
|
||||
void notify(int state, unsigned char *msg, size_t size); // call on socketThread
|
||||
int openTCP(bool isIpv6); // call on socketThread
|
||||
void closeTCP(); // call on socketThread
|
||||
int recvTCP(); // call on socketThread
|
||||
int sendTCP(unsigned char *buff, size_t size); // call on socketThread
|
||||
|
||||
int _tcp;
|
||||
std::string _host;
|
||||
int _port;
|
||||
std::function<void(int state, unsigned char *msg, size_t size)> _cb;
|
||||
bool _quit;
|
||||
|
||||
std::thread *_thread;
|
||||
std::queue<TCPData *> sendQueue; // send to server
|
||||
std::mutex sendMutex;
|
||||
std::queue<TCPData *> getQueue; // get from server
|
||||
std::mutex getMutex;
|
||||
};
|
||||
|
||||
#endif // __ASYNC_TCP_H__
|
||||
@@ -1,9 +1,11 @@
|
||||
set(COCOS_NETWORK_SRC
|
||||
network/Uri.cpp
|
||||
network/WebSocket.cpp
|
||||
network/AsyncTCP.cpp
|
||||
)
|
||||
|
||||
set(COCOS_NETWORK_HEADER
|
||||
network/Uri.h
|
||||
network/WebSocket.h
|
||||
network/AsyncTCP.h
|
||||
)
|
||||
|
||||
@@ -21,6 +21,7 @@ set(lua_bindings_manual_headers
|
||||
manual/network/lua_extensions.h
|
||||
manual/network/lua_http_manual.h
|
||||
manual/network/CCHTTPRequest.h
|
||||
manual/network/Lua_AsyncTCP.h
|
||||
manual/Lua-BindingsExport.h
|
||||
manual/tolua_fix.h
|
||||
manual/navmesh/lua_cocos2dx_navmesh_manual.h
|
||||
@@ -64,6 +65,7 @@ set(lua_bindings_manual_files
|
||||
manual/network/Lua_web_socket.cpp
|
||||
manual/network/lua_http_manual.cpp
|
||||
manual/network/CCHTTPRequest.cpp
|
||||
manual/network/Lua_AsyncTCP.cpp
|
||||
manual/spine/lua_cocos2dx_spine_manual.cpp
|
||||
manual/spine/lua_spSkeletonData.cpp
|
||||
manual/spine/LuaSkeletonAnimation.cpp
|
||||
|
||||
179
cocos/scripting/lua-bindings/manual/network/Lua_AsyncTCP.cpp
Normal file
179
cocos/scripting/lua-bindings/manual/network/Lua_AsyncTCP.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
// Copyright 2020 KeNan Liu
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "network/AsyncTCP.h"
|
||||
#include "scripting/lua-bindings/manual/tolua_fix.h"
|
||||
|
||||
#include "scripting/lua-bindings/manual/CCLuaStack.h"
|
||||
#include "scripting/lua-bindings/manual/CCLuaValue.h"
|
||||
#include "scripting/lua-bindings/manual/CCLuaEngine.h"
|
||||
#include "scripting/lua-bindings/manual/LuaBasicConversions.h"
|
||||
#include "scripting/lua-bindings/manual/cocos2d/LuaScriptHandlerMgr.h"
|
||||
|
||||
using namespace cocos2d;
|
||||
|
||||
static int lua_AsyncTCP_create(lua_State* tolua_S)
|
||||
{
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
tolua_Error tolua_err;
|
||||
if (!tolua_isusertable(tolua_S, 1, "AsyncTCP", 0, &tolua_err)) goto tolua_lerror;
|
||||
#endif
|
||||
|
||||
do {
|
||||
AsyncTCP *asyncTCP = new (std::nothrow) AsyncTCP();
|
||||
tolua_pushusertype(tolua_S, (void*)asyncTCP, "AsyncTCP");
|
||||
tolua_register_gc(tolua_S, lua_gettop(tolua_S));
|
||||
return 1;
|
||||
} while (0);
|
||||
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
tolua_lerror:
|
||||
tolua_error(tolua_S,"#ferror in function 'lua_AsyncTCP_create'.",&tolua_err);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int lua_AsyncTCP_setEventCB(lua_State* tolua_S)
|
||||
{
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
tolua_Error tolua_err;
|
||||
if (!tolua_isusertype(tolua_S, 1, "AsyncTCP", 0, &tolua_err)
|
||||
|| !toluafix_isfunction(tolua_S, 2, "LUA_FUNCTION", 0, &tolua_err))
|
||||
goto tolua_lerror;
|
||||
#endif
|
||||
do {
|
||||
AsyncTCP *self = (AsyncTCP *)tolua_tousertype(tolua_S, 1, 0);
|
||||
if (self) {
|
||||
int handler = toluafix_ref_function(tolua_S, 2, 0);
|
||||
|
||||
self->setEventCB([=](int state, unsigned char *buff, size_t size) {
|
||||
LuaStack *stack = LuaEngine::getInstance()->getLuaStack();
|
||||
stack->pushInt(state);
|
||||
if (buff) {
|
||||
stack->pushString((const char*)buff, size);
|
||||
} else {
|
||||
stack->pushNil();
|
||||
}
|
||||
stack->executeFunctionByHandler(handler, 2);
|
||||
});
|
||||
|
||||
ScriptHandlerMgr::getInstance()->removeObjectAllHandlers((void*)self);
|
||||
ScriptHandlerMgr::getInstance()->addCustomHandler((void*)self, handler);
|
||||
}
|
||||
return 0;
|
||||
} while (0);
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
tolua_lerror:
|
||||
tolua_error(tolua_S,"#ferror in function 'lua_AsyncTCP_setEventCB'.", &tolua_err);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int lua_AsyncTCP_open(lua_State* tolua_S)
|
||||
{
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
tolua_Error tolua_err;
|
||||
if (!tolua_isusertype(tolua_S, 1, "AsyncTCP", 0, &tolua_err)
|
||||
|| !tolua_isstring(tolua_S, 2, 0, &tolua_err)
|
||||
|| !tolua_isnumber(tolua_S, 3, 0, &tolua_err))
|
||||
goto tolua_lerror;
|
||||
#endif
|
||||
do {
|
||||
AsyncTCP *self = (AsyncTCP *)tolua_tousertype(tolua_S, 1, 0);
|
||||
if (self) {
|
||||
const char *host = lua_tostring(tolua_S, 2);
|
||||
int port = lua_tointeger(tolua_S, 3);
|
||||
self->open(host, port);
|
||||
}
|
||||
return 0;
|
||||
} while (0);
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
tolua_lerror:
|
||||
tolua_error(tolua_S,"#ferror in function 'lua_AsyncTCP_open'.", &tolua_err);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int lua_AsyncTCP_send(lua_State* tolua_S)
|
||||
{
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
tolua_Error tolua_err;
|
||||
if (!tolua_isusertype(tolua_S, 1, "AsyncTCP", 0, &tolua_err)
|
||||
|| !tolua_isstring(tolua_S, 2, 0, &tolua_err))
|
||||
goto tolua_lerror;
|
||||
#endif
|
||||
do {
|
||||
AsyncTCP *self = (AsyncTCP *)tolua_tousertype(tolua_S, 1, 0);
|
||||
if (self) {
|
||||
const char *data = lua_tostring(tolua_S, 2);
|
||||
size_t size = lua_objlen(tolua_S, 2);
|
||||
self->send((unsigned char *)data, size);
|
||||
}
|
||||
return 0;
|
||||
} while (0);
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
tolua_lerror:
|
||||
tolua_error(tolua_S,"#ferror in function 'lua_AsyncTCP_send'.", &tolua_err);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int lua_AsyncTCP_close(lua_State* tolua_S)
|
||||
{
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
tolua_Error tolua_err;
|
||||
if (!tolua_isusertype(tolua_S, 1, "AsyncTCP", 0, &tolua_err))
|
||||
goto tolua_lerror;
|
||||
#endif
|
||||
do {
|
||||
AsyncTCP *self = (AsyncTCP *)tolua_tousertype(tolua_S, 1, 0);
|
||||
if (self) {
|
||||
self->close();
|
||||
}
|
||||
return 0;
|
||||
} while (0);
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
tolua_lerror:
|
||||
tolua_error(tolua_S,"#ferror in function 'lua_AsyncTCP_close'.", &tolua_err);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int lua_gc_AsyncTCP(lua_State* tolua_S)
|
||||
{
|
||||
AsyncTCP *self = (AsyncTCP *)tolua_tousertype(tolua_S, 1, 0);
|
||||
ScriptHandlerMgr::getInstance()->removeObjectAllHandlers((void*)self);
|
||||
delete self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
TOLUA_API int register_AsyncTCP_manual(lua_State* tolua_S)
|
||||
{
|
||||
AsyncTCP::initEnv(); // init library
|
||||
|
||||
tolua_open(tolua_S);
|
||||
tolua_usertype(tolua_S, "AsyncTCP");
|
||||
tolua_cclass(tolua_S, "AsyncTCP", "AsyncTCP", "cc.Ref", lua_gc_AsyncTCP);
|
||||
tolua_beginmodule(tolua_S, "AsyncTCP");
|
||||
tolua_function(tolua_S, "create", lua_AsyncTCP_create);
|
||||
tolua_function(tolua_S, "setEventCB", lua_AsyncTCP_setEventCB);
|
||||
tolua_function(tolua_S, "open", lua_AsyncTCP_open);
|
||||
tolua_function(tolua_S, "send", lua_AsyncTCP_send);
|
||||
tolua_function(tolua_S, "close", lua_AsyncTCP_close);
|
||||
tolua_endmodule(tolua_S);
|
||||
return 1;
|
||||
}
|
||||
28
cocos/scripting/lua-bindings/manual/network/Lua_AsyncTCP.h
Normal file
28
cocos/scripting/lua-bindings/manual/network/Lua_AsyncTCP.h
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2020 KeNan Liu
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __LUA_ASYNCTCP_H__
|
||||
#define __LUA_ASYNCTCP_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "tolua++.h"
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
TOLUA_API int register_AsyncTCP_manual(lua_State* tolua_S);
|
||||
|
||||
#endif //__LUA_ASYNCTCP_H__
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "scripting/lua-bindings/manual/network/lua_extensions.h"
|
||||
#include "scripting/lua-bindings/manual/network/Lua_web_socket.h"
|
||||
#include "scripting/lua-bindings/manual/network/lua_http_manual.h"
|
||||
#include "scripting/lua-bindings/manual/network/Lua_AsyncTCP.h"
|
||||
#include "scripting/lua-bindings/manual/CCLuaEngine.h"
|
||||
#include "cocos/platform/CCNetwork.h"
|
||||
#include "base/CCDirector.h"
|
||||
@@ -228,15 +229,16 @@ TOLUA_API int register_network_manual(lua_State* L)
|
||||
|
||||
int register_network_module(lua_State* L)
|
||||
{
|
||||
lua_getglobal(L, "_G");
|
||||
if (lua_istable(L,-1))//stack:...,_G,
|
||||
{
|
||||
luaopen_lua_extensions(L);
|
||||
register_web_socket_manual(L);
|
||||
register_http_manual(L);
|
||||
register_network_manual(L);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
lua_getglobal(L, "_G");
|
||||
if (lua_istable(L,-1))//stack:...,_G,
|
||||
{
|
||||
luaopen_lua_extensions(L);
|
||||
register_web_socket_manual(L);
|
||||
register_http_manual(L);
|
||||
register_AsyncTCP_manual(L);
|
||||
register_network_manual(L);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ function MainScene:ctor()
|
||||
"Test_Spine",
|
||||
"Test_RichText",
|
||||
"Test_TMXTiledMap",
|
||||
"Test_AsyncTCP",
|
||||
}
|
||||
|
||||
local scrollView = ccui.ScrollView:create()
|
||||
|
||||
71
tests/src/app/views/Test_AsyncTCP.lua
Executable file
71
tests/src/app/views/Test_AsyncTCP.lua
Executable file
@@ -0,0 +1,71 @@
|
||||
local BaseLayer = require("app.scenes.BaseLayer")
|
||||
|
||||
local TestCase = class("Test_WebSocket", BaseLayer)
|
||||
|
||||
-- sync from AsyncTCP.h
|
||||
local EVENT_CONNECTING = 0
|
||||
local EVENT_FAILED = 1
|
||||
local EVENT_CONNECTED = 2
|
||||
local EVENT_CLOSED = 3
|
||||
local EVENT_DATA = 4
|
||||
|
||||
function TestCase:ctor()
|
||||
self.super.ctor(self)
|
||||
|
||||
self:setNodeEventEnabled(true)
|
||||
-- tips
|
||||
local label = display.newTTFLabel({
|
||||
text = "Async TCP",
|
||||
size = 25,
|
||||
color = cc.c3b(255, 255, 255),
|
||||
})
|
||||
label:align(display.CENTER, display.cx, display.cy + 200)
|
||||
self:addChild(label)
|
||||
|
||||
local btn = ccui.Button:create()
|
||||
:pos(display.cx, 200)
|
||||
:addTo(self)
|
||||
btn:setTitleText("Click me to test")
|
||||
btn:setTitleFontSize(30)
|
||||
btn:setTitleColor(cc.c3b(255, 255, 0))
|
||||
btn:addTouchEventListener(function(sender, eventType)
|
||||
if 2 == eventType then
|
||||
print(self.asyncTCP)
|
||||
if self.asyncTCP then return end
|
||||
|
||||
self.asyncTCP = AsyncTCP:create()
|
||||
self.asyncTCP:setEventCB(handler(self, self.onTCPEvent))
|
||||
self.asyncTCP:open("fe80::1c5c:f42e:369f:e11a%en0", 1234)
|
||||
|
||||
self:performWithDelay(function()
|
||||
if self.asyncTCP then
|
||||
self.asyncTCP:close()
|
||||
end
|
||||
end, 3)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function TestCase:onTCPEvent(state, data)
|
||||
if state == EVENT_CONNECTING then
|
||||
print("** AsyncTCP connecting **")
|
||||
elseif state == EVENT_FAILED then
|
||||
print("** AsyncTCP failed **")
|
||||
self.asyncTCP = nil
|
||||
elseif state == EVENT_CONNECTED then
|
||||
self.asyncTCP:send("Hello AsyncTCP")
|
||||
elseif state == EVENT_DATA then
|
||||
print(data)
|
||||
elseif state == EVENT_CLOSED then
|
||||
print("** AsyncTCP closed **")
|
||||
self.asyncTCP = nil
|
||||
end
|
||||
end
|
||||
|
||||
function TestCase:onExit()
|
||||
if self.asyncTCP then
|
||||
self.asyncTCP:close()
|
||||
end
|
||||
end
|
||||
|
||||
return TestCase
|
||||
Reference in New Issue
Block a user