[SOLVED] TCP Socket Library

Hi,

Is there any tcp socket library which allow cocos2d-x game to connect to a socket server and enable send/receive of strings.

I am not looking for Websockets / Socket.IO or any other service based platforms. My primary targets for game are android and iOS and porting an existing flash game to cocos2d-x. So want to use same tcp socket server.

Any example would be great.

Thanks

hi,

still not able to find any example. any help?

Thanks

You can use the sys socket library on both platforms

http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html

http://pubs.opengroup.org/onlinepubs/009696699/basedefs/sys/socket.h.html

I’ve used it on a few projects in the past

I’d used C++ Asio, It’s great that easy to understand and implement, also fully compatible with Android and ios.

Thanks @almax27 for sharing link. This looks little low-level to me. I have experience with Netty (Java) for server development and then Unity3D for client for same. Both provide high-level methods so it was easy.

@hainh After exploring Asio, I think it is easy to understand. Is there any tutorial about integrating C++ Asio with Cocos2d-X for iOS and Android? Or if you can share some working code + first time setup guidelines.

Thanks

@devilzk
try this

That’s hard (the tutorial) :smile:

Firstly you just have to include Asio Standalone to your project like every others C++ source code files and headers.

Then try out the tutorial on Asio docs. You’ll find it super easy.

Hi @hainh,

So I downloaded Asio standalone from think-async website and then compiled it without boost. Then used tcp_client example as refernece and was able to set connection successfully to my socket server.

asio::io_service io_service;

tcp::socket s(io_service);
tcp::resolver resolver(io_service);
resolver.resolve({"127.0.0.1", "8007"});
asio::connect(s, resolver.resolve({"localhost", "8007"}));

As soon as this execute, I can see 1 active connection to my server. My server is sending a JSON string message to all connections upon connection.

{"c":-1,"s":"SessionIdGoesHere","v":"1.0.1","timestamp":1462947301}

So I tried to read that message in next line. However facing an issue with that.

char reply[1024];
size_t reply_length = asio::read(s, asio::buffer(reply, 1024));
CCLOG("%s", reply);

If I set 1024 to any lower number say 10 or 25, it shows a message. But if I set it to a higher number (max_length constant which is set to 1024), it doesn’t show any response.

Is there any way to configure Asio to read incoming messages which are \n delimited and then return a std::string out of that?

Also right now my code is in HelloWorldScene, but eventually it needs to be in a separate thread. Because other wise it will cause lag in animations if run in main cocos2d-x thread (please correct me if its not the case). So how do I setup it as a separate thread and then have callbacks / event dispatch whenever there is a message.

Example I am finding are for Boost::Asio (not Asio standalone). So if I should use Boost:Asio instead of Asio standalone?

https://valelab.ucsf.edu/svn/3rdpartypublic/boost/doc/html/boost_asio/example/timeouts/async_tcp_client.cpp

Made some progress, able to read full message. Now need to figure out how to make this async and raise events to my main game class with inbound messages. Also need to figure how to add error handling.

std::string msg;
asio::streambuf b;
asio::read_until(s, b, "\n");
std::istream is(&b);
is >> msg;
CCLOG("%s", msg.c_str());

Hi @hainh / @camkadev / @almax27,

I made some good progress over Boost.Asio integration with cocos2d-x project. First I was trying with Asio standalone but then found a git script ([faithfracture’s Boost build script][1]), and using that compiled framework for boost_1_60_0. Then to get comfortable with library, took its async tcp example and played with it as a standalone command line application along with thread.

After that linked iOS framework to cocos2d-x project and then copied modified version of tcp example to cocos2d-x project. And with some small code, my cocos2d-x game now connects to socket server and also can read / write string messages.

But then encountered a issue with threading :confused:

GameManager:InitConnection()
{
	boost::asio::io_service io_service;
	tcp::resolver r(io_service);
	
	//TCPSocketClient is async tcp client 
	TCPSocketClient tcp_client(io_service);

	//my socket server is running on port 8007 on same machine 
	tcp_client.start(r.resolve(tcp::resolver::query("127.0.0.1", "8007")));

	/**
	 When boost::thread is used to run boost event loop in separate thread, 
	 so that cocos2d-x's default game loop (scene rendering etc work fine)
	 it crashes.
	*/
	boost::thread bt(boost::bind(&boost::asio::io_service::run, &io_service));

	//However if instead of thread I do a sync run, then it works fine.
	//io_service.run();
}

GameManager is a singleton class, which is similar to https://gist.github.com/solkar/8651478

In AppDelegate.cpp , after director->runWithScene(scene);, I am calling GameManager’s InitConnection.

GameManager * mgr = GameManager::getInstance();
mgr->InitConnection();

And it seems to work as long as I keep boost’s io_service run in main loop. But then it prevent cocos2d-x scene execution further. and if I keep io_service loop inside a boost::thread (as in above snippet), right after the launch, simulator crashes.

I think its something related to weak reference, but can’t figure out. Any help?

Thanks
[1]: https://gist.github.com/faithfracture/c629ae4c7168216a9856 “faithfracture’s Boost Build Script”

Hello @devilzk, I’m happy that you’ve made a big progress.

To the crash, you need a message dispatching mechanism. Whenever you get a message, enqueue it in a queue from your asio io_service thread, then in Cocos2dx create an update callback that checks the message queue to find are there any message. If there are, you can safely dispatch all to your messages 'cause you are in the right thread. Note that this queue is accessed by 2 threads, so use a lock guard on the queue properly.

@hainh,

Yes, I got the idea of callback / message forwarding. But my problem is that its crashing immediately after start.

and that crash happen if I use boost::thread to run io_service run loop. If I don’t use a separate thread using boost::thread but simply call io_service.run() in next line, everything works fine except that now cocos2d-x UI is not updated because of blocking nature of io_service.run().

For message callbacks, I think I can call a method of my singleton class GameManager->getInstance()->handle_message(const char *message) and inside that can process that. Yet I have to experiment with this approach, but right now this crash is big concern. Because its not allowing me to create a new thread and rather keep crashing immediately after launch if i use boost::thread for io_service run method.

If having this code may give you more idea, I can push it to github or somewhere else and share link with you.

Thanks

Don’t hesitate to post it, if I can’t help, many others can :smiley:

I don’t have any experience with boost, here is the C++11 code I used to run the service in another thread:

_service_thread = std::move(std::thread([this]() {
    _io_service.run();
}));

hi @hainh,

Here is link for Classes folder. http://www.filedropper.com/classes_1

I tried both pre-compiled boost library https://github.com/danoli3/ofxiOSBoost as well compiled my own using a script I shared link earlier, without any difference in issue, which still persist.

Thanks

Thanks everyone, issue is solved now. I will write a blog post about everything and share link here for any one else having similar issue in future.

2 Likes

That’s great!

PS: it’s too late, but now I notice that you used io_service as local variable. Didn’t realized till seeing your classes folder. :facepalm: