cocos2d-x3.2 network Programming with server-side framework Firefly (primary network communication)

Source: Internet
Author: User
Tags error code set socket socket strlen win32

Long time no writing, recently in the Research Service Framework Firefly and Pomelo, as a rookie I did take a lot of effort to understand some of the source code. Originally intended to play under the pomelo, but I have to say that this thing is really for professional developers, I engaged in a half-day libpomelo also not smooth link on the server, just link server is so difficult to do, let alone communication, what can I say? (really is the network material has been turned over, really do not know how others are used), the official example does not have the simple code, so not suitable for the super rookie like me to use, in contrast, Firefly more easy to get started, there are many types of source code, simple and systematic full level of all have, Seriously study the words can really learn a lot of things ...

Because the official network communication Protocol example is only Python client source code, so for small white, may not know how to implement in the Cocos2d-x project VC + +, which is also considered an added tutorial. Also, as before, the study of the contents of the record for later use, hoping for beginners can also be helpful ...

Firefly is an open-source game server framework, can be directly to nine seconds Community download installation, here does not say the installation process, I use the new version of the Gfirefly, this is also available on GitHub download, installation will be troublesome, say a long time not updated alas ... Have you been busy Crossapp projects lately?

cocos2d-x3.2 needs to use VS2012, which has a new c++11 feature that is quite handy on threading and no longer relies on third-party pthread

In general, the COCOS2DX is used in the HTTP class of short link communication, but I want to record here is to use the socket and the server to interact with, in a platform like Linux, generally used is BSD socket, this is not a third-party plug-in, but Unix/ Linux system, which is also used in cross-platform use is not a problem, this example is just testing the code on Windows, not on the phone really tested, but should be similar.

In the source code of the Firefly, you can generally see the folder containing a network, which has the methods and classes used in the Internet communication, is a hit a package, the following is just the core of the code to take out the modified use:

The three most important methods of socket are:

Connect () for linked servers

Send () is used to send messages to the server

Recv () to receive messages returned by the server

itself using the above things is not difficult, for small white, really need to know is Firefly communication protocol, if you send the message format in the client and Firefly message format is not the same, that Firefly will fly directly out of a paragraph of English, meaning is probably "received an illegal packet, Unable to identify. " So here's a look at Firefly's communication protocol.

The following header information is required in the message sent to the Firefly server (which is available in the official tutorial):

Class Message:public Ccobject
{public
:
	
    
    Char HEAD0;
    char HEAD1;
    char HEAD2;
    char HEAD3;
    char protoversion;
    
    byte serverversion[4];
    byte length[4];
    byte commandid[4];
    /**
      * The data of the message * */
    char*;
	
	
	
	
	Message ();
    int datalength ();
	~message ();
};

The declaration definition above until CommandID is the message header, which is the protocol header, which is used to identify the basic information of the message, such as protocol version protoversion, length of the entire message packet, The command number CommandID (can be used to perform the identification number of the specified service-side function function) ... data is the content of the message body we want to transmit, which is a ccobject-based message object defined in the client. Next look at the server, the following code from the game "Smoke ol" server source code, as long as the copy to the new Firefly project can be used:

From Gfirefly.server.globalobject import globalobject from
gfirefly.netconnect.datapack import Datapackprotoc


def callwhenconnlost (conn):
    dynamicid = Conn.transport.sessionno
    globalobject (). remote[' Gate '. Callremote ("Netconnlost_2", Dynamicid)
    print (' A link has been disconnected ')

def creatversionresult (netversion):
    return Netversion

def doconnectionmade (conn):
    print (' successfully established a link ')
    
Dataprotocl = Datapackprotoc ( 78,37,38,48,9,0)
Globalobject (). NETFACTORY.SETDATAPROTOCL (DATAPROTOCL)

globalobject (). Netfactory.doconnectionlost = Callwhenconnlost
globalobject (). Netfactory.doconnectionmade = DoConnectionMade From


gfirefly.server.globalobject import remoteservicehandle from
gfirefly.server.globalobject Import Netservicehandle


@netserviceHandle
def echo_1 (_conn,data):
    print (data)
    return Data

def Echo_2 (showtext):
    print (showtext);
    Return Showtext

The following paragraph is used to define the protocol header code, respectively, corresponding to the previous client on the definition of the first 6 parameters, if sent to the package does not contain the same format and the corresponding information, it will not be resolved by the server
DATAPROTOCL = Datapackprotoc (78,37,38,48,9,0)

The above also defines a function named Echo_1, the following _1 is the ID of Firefly with the recognition function function, absolutely cannot repeat, when we send a message from the client, if the specified CommandID parameter is 1, the server will execute echo_1 when receiving this message , the returned return is used to return the corresponding data to the client, and the service-side code is done.

Take a look at the message constructor, which is also from the Firefly official release of the game source code:

message* networkmanager::constructmessage (const char* data,int commandId) {message* msg = new Message ();
    msg->head0=78;
    msg->head1=37;
    msg->head2=38;
    msg->head3=48;
    
    msg->protoversion=9;
    int a=0;
    Msg->serverversion[3]= (Byte) (0xff&a);;
    Msg->serverversion[2]= (Byte) ((0xff00&a) >>8);
    Msg->serverversion[1]= (Byte) ((0xff0000&a) >>16);
    
    Msg->serverversion[0]= (Byte) ((0xff000000&a) >>24);
    
    int B=strlen (data) +4;
    Msg->length[3]= (Byte) (0xff&b);;
    Msg->length[2]= (Byte) ((0xff00&b) >>8);
    Msg->length[1]= (Byte) ((0xff0000&b) >>16);
    
    Msg->length[0]= (Byte) ((0xff000000&b) >>24);
    int c=commandid;
    Msg->commandid[3]= (Byte) (0xff&c);;
    Msg->commandid[2]= (Byte) ((0xff00&c) >>8);
    Msg->commandid[1]= (Byte) ((0xff0000&c) >>16);
 Msg->commandid[0]= (Byte) ((0xff000000&c) >>24);   
    Str.append (MSG->HEAD0);
    printf ("%d", msg->datalength ());
    Msg->data = new Char[msg->datalength ()];
    memcpy (msg->data+0,&msg->head0,1);
    memcpy (msg->data+1,&msg->head1,1);
    memcpy (msg->data+2,&msg->head2,1);
    memcpy (msg->data+3,&msg->head3,1);
    memcpy (msg->data+4,&msg->protoversion,1);
    memcpy (msg->data+5,&msg->serverversion,4);
    memcpy (msg->data+9,&msg->length,4);
    memcpy (msg->data+13,&msg->commandid,4);
    memcpy (Msg->data+17,data,strlen (data));
    memcpy (Msg->data+position,bytes+offset,len);
	Msg->data = data;
return msg; }
The above code encapsulates the message in a sequential order, wrapping it into data, making it a complete packet, and finally returning the message object.

Then there's the link server, and here's the code:

BOOL Networkmanager::connect () {
	mlock.lock ();
	Determine if the initial link initialization under Windows platform is successful
	if (Init () ==-1) {
		return false;
	}
	Determines whether the socket was created successfully
	if (Create (af_inet,sock_stream,0) ==false) {
	return false;
	};
	Set socket to non-blocking mode
	/*int RetVal;
	unsigned long ul = 1;
	Retval=ioctlsocket (M_sock, Fionbio, &ul);
	if (retval==socket_error) {
		Cclog ("set blocking parameter Error");
		Closesocket (m_sock);  
		#ifdef WIN32
		wsacleanup ();
		#endif
	}*/
	//using the Created Socket link server
	struct sockaddr_in svraddr;
	svraddr.sin_family = af_inet;
	SVRADDR.SIN_ADDR.S_ADDR = inet_addr (ip_address);
	Svraddr.sin_port = htons (ip_host);

	int ret = connect (m_sock, struct sockaddr*) &svraddr, sizeof (SVRADDR));
	if (ret = = socket_error) {
		/*closesocket (m_sock);
		#ifdef WIN32
		wsacleanup ();
		#endif *

		/Cclog ("link failed");
			After successful link, start sending data to server
	//sendthread ();
    Recvthread ();

		return false;
	}
	After successful link, start sending data to server
	sendthread ();
	Cclog ("link successed");
	Mlock.unlock ();

	return true;
}

You can see the end of the link code above has joined the execution of the sending data function, the implementation code sent is actually very simple, the following is sent a "Getsendmessage successful!" Information to the server, and if the server receives this message, it will also output a message in log:

void Networkmanager::sendthread () {
		message* msg=constructmessage ("Getsendmessage successful!", 1);
		Send Message
		Send (Msg->data,msg->datalength (), 0);
}

After sending the message, you can start listening to the data returned by the receiving server, the following is only the basic code, does not contain data parsing, received the message returned by the server can see the log output information:

void Networkmanager::recvfunc () {
	char recvbuf[17];
	Fd_zero (&fdread);
	Fd_set (m_sock,&fdread);
	Mlock.lock ();
		struct Timeval	aTime;
	Atime.tv_sec = 5;
	atime.tv_usec = 0;
	
	int ret = SELECT (M_sock,&fdread,null,null,&atime);

if (Fd_isset (m_sock,&fdread))
{
	cclog ("Socket state=%d", ret);
	if (ret==1) {
		//First get the protocol header data, according to the information inside to determine which callback functions should be called for next data processing
		//while (true) {
		int getrevdatalength=recv (m_ sock,recvbuf,17,0);
		if (getrevdatalength==17) {
			cclog ("Recvthread ok,getdataprocess=%d", getrevdatalength);			
		} else{
			Cclog ("The Connect has terminated! Revdata is not completed! ");
			Cclog ("The ERROR code:%d", WSAGetLastError ()); 
		Closesocket (M_sock);}}}

else{
	cclog ("Select sock Error");
}
	Mlock.unlock ();
}

Execute receive thread
void Networkmanager::recvthread () {
	//Open a T2 thread, the entry function is Recvfunc ()
	std::thread T2 (& Networkmanager::recvfunc,this);	
	T2.join ();
}

After the final execution of the code, you can see the message we sent on the server, as shown below


This completes the communication session with the server.

Because I study the code function implementation of random code to write the bad habit, so the source code may be some superfluous and non-standard things, please forgive me. VS2012 Client project source code can be downloaded at the following address:

http://download.csdn.net/detail/cyistudio/8004925

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.