cocos2dx长连接BSDSocke网络通信

来源:互联网 发布:手机淘宝 5.9.5旧版本 编辑:程序博客网 时间:2024/05/16 18:02

一、Socket网络通信一般流程

服务器Socket的一般流程:

(1)创建服务器Socket(Create);

(2)绑定端口(Bind);

(3)开启监听(Listener);

(4)接收客户端请求(Accept)。

(5)给客户端发送和接收数据(Send,Recv)

客户端的一般流程:

(1)创建客户端Socket(Create);

(2)连接服务器(Connect);

(3)发送和接收数据(Send,Recv)。

二、代码实例:

客户端:

HelloWorldScene.h:

#ifndef __HELLOWORLD_SCENE_H__#define __HELLOWORLD_SCENE_H__#include "cocos2d.h"#include "ODSocket.h"class HelloWorld : public cocos2d::Layer{public:    static cocos2d::Scene* createScene();    virtual bool init();~HelloWorld();std::thread * t1;ODSocket * sock_client;string strmsg;void update(float t);static void * getMessage( );    CREATE_FUNC(HelloWorld);};#endif // __HELLOWORLD_SCENE_H__
HelloWorldScene.cpp:

#include "HelloWorldScene.h"#include "cocos-ext.h"#include "ODSocket.h"#include <thread>#include <iostream>using namespace cocos2d::extension;USING_NS_CC;using namespace std;static HelloWorld * nowHelloWorld;HelloWorld::~HelloWorld(){t1->join();//调用join阻塞,等待线程执行完毕。//或者调用detach放到后台,不过放到后台你就没法控制它了。CC_SAFE_DELETE(t1);//相当于delete t1;t1 = nullptr;}Scene* HelloWorld::createScene(){// 'scene' is an autorelease objectauto scene = Scene::create();// 'layer' is an autorelease objectauto layer = HelloWorld::create();// add layer as a child to scenescene->addChild(layer);// return the scenereturn scene;}bool HelloWorld::init(){if (!Layer::init()){return false;}Size visibleSize = Director::getInstance()->getVisibleSize();Vec2 origin = Director::getInstance()->getVisibleOrigin();//背景图Sprite * bg = Sprite::create("common/MainScene.jpg");bg->setScaleX(visibleSize.width / bg->getContentSize().width);bg->setScaleY(visibleSize.height / bg->getContentSize().height);bg->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));addChild(bg);CCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", 24);pLabel->setTag(111);// position the label on the center of the screenpLabel->setPosition(ccp(origin.x + visibleSize.width / 2,origin.y + visibleSize.height - pLabel->getContentSize().height));//add the label as a child to this layerthis->addChild(pLabel, 1);nowHelloWorld = this;//初始化Socket对象sock_client = new ODSocket();//连结到Socket服务器,显示从服务器发送过来的内容到场景sock_client->Init();bool res = sock_client->Create(AF_INET, SOCK_STREAM, 0);log("\nCocos2dx_socket_created:%d", res);//连接服务器res = sock_client->Connect("192.168.1.211", 8889);log("\nconnect_succeed:%d", res);//接收从服务器发过来的消息if (res == 1){//创建线程对象t1 = new std::thread(HelloWorld::getMessage);log("thread create succeed!");}this->scheduleUpdate();return true;}void * HelloWorld::getMessage( ) {char buf[1024];while (1) {buf[0] = 0;nowHelloWorld->sock_client->Recv(buf, sizeof(buf));if (strlen(buf)>10){log("buf:%s", buf);nowHelloWorld->strmsg = buf;}}}void HelloWorld::update(float t) {//在当前场景中显示从服务器发送过来的消息CCLabelTTF * labelMsg = (CCLabelTTF *)nowHelloWorld->getChildByTag(111);labelMsg->setString(strmsg.c_str());}

服务器端:

SocketServer.cpp:

#include  <iostream>#include "ODSocket.h"#include <string.h>     using namespace std;int main(int argc,const char* argv[]){    ODSocket *sockServer = new ODSocket();    sockServer->Init();    bool res = sockServer->Create(AF_INET,SOCK_STREAM,0);    cout<<"\nsocket_create"<<res<<endl;  //返回值为1表示成功,下同。    res = sockServer->Bind(8889);    cout<<"port:%d"<<res<<endl;    res = sockServer->Listen();    cout<<"port_listen:%d"<<res<<endl;    char message[30];    ODSocket * p_sockClient = new ODSocket();    char * address = new char[20];    sockServer->Accept(*p_sockClient,address);    cout<<"\n%s come!"<<address<<endl;    while(1)    {        cin>>address;        if(strcmp(address,"exit")==0)        {            break;        }        sprintf(message,"welcome %s",address);        p_sockClient->Send(message,sizeof(message));    }    p_sockClient->Close();    sockServer->Clean();    return 0;}
附录:

ODSocket.h:

#ifndef _ODSOCKET_H_#define _ODSOCKET_H_#ifdef WIN32#include <winsock.h>typedef intsocklen_t;#else#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <fcntl.h>#include <unistd.h>#include <sys/stat.h>#include <sys/types.h>#include <arpa/inet.h>typedef intSOCKET;//#pragma region define win32 const variable in linux#define INVALID_SOCKET-1#define SOCKET_ERROR-1//#pragma endregion#endif#include <iostream>using namespace std;class ODSocket {public:ODSocket(SOCKET sock = INVALID_SOCKET);~ODSocket();// Create socket object for snd/recv databool Create(int af, int type, int protocol = 0);// Connect socketbool Connect(const string ip, unsigned short port);//#region server// Bind socketbool Bind(unsigned short port);// Listen socketbool Listen(int backlog = 5);// Accept socketbool Accept(ODSocket& s, char* fromip = NULL);//#endregion// Send socketint Send(const char* buf, int len, int flags = 0);// Recv socketint Recv(char* buf, int len, int flags = 0);// Close socketint Close();// Get errnoint GetError();//#pragma region just for win32// Init winsock DLL static int Init();// Clean winsock DLLstatic int Clean();//#pragma endregion// Domain parsestatic bool DnsParse(const char* domain, char* ip);ODSocket& operator = (SOCKET s);operator SOCKET ();public:SOCKET m_sock;};#endif
ODSocket.cpp:

#include "ODSocket.h"#ifdef WIN32#pragma comment(lib, "wsock32")#endifODSocket::ODSocket(SOCKET sock){m_sock = sock;}ODSocket::~ODSocket(){}int ODSocket::Init(){#ifdef WIN32/*http://msdn.microsoft.com/zh-cn/vstudio/ms741563(en-us,VS.85).aspxtypedef struct WSAData {WORD wVersion;//winsock versionWORD wHighVersion;//The highest version of the Windows Sockets specification that the Ws2_32.dll can supportchar szDescription[WSADESCRIPTION_LEN+1];char szSystemStatus[WSASYSSTATUS_LEN+1];unsigned short iMaxSockets;unsigned short iMaxUdpDg;char FAR * lpVendorInfo;}WSADATA, *LPWSADATA;*/WSADATA wsaData;//#define MAKEWORD(a,b) ((WORD) (((BYTE) (a)) | ((WORD) ((BYTE) (b))) << 8)) WORD version = MAKEWORD(2, 0);int ret = WSAStartup(version, &wsaData);//win sock start upif (ret) {//cerr << "Initilize winsock error !" << endl;return -1;}#endifreturn 0;}//this is just for windowsint ODSocket::Clean(){#ifdef WIN32return (WSACleanup());#endifreturn 0;}ODSocket& ODSocket::operator = (SOCKET s){m_sock = s;return (*this);}ODSocket::operator SOCKET (){return m_sock;}//create a socket object win/lin is the same// af:bool ODSocket::Create(int af, int type, int protocol){m_sock = socket(af, type, protocol);if (m_sock == INVALID_SOCKET) {return false;}return true;}bool ODSocket::Connect(const string ip, unsigned short port){struct sockaddr_in svraddr;svraddr.sin_family = AF_INET;svraddr.sin_addr.s_addr = inet_addr(ip.c_str());svraddr.sin_port = htons(port);int ret = connect(m_sock, (struct sockaddr*)&svraddr, sizeof(svraddr));if (ret == SOCKET_ERROR) {return false;}return true;}//for serverbool ODSocket::Bind(unsigned short port){struct sockaddr_in svraddr;svraddr.sin_family = AF_INET;svraddr.sin_addr.s_addr = INADDR_ANY;svraddr.sin_port = htons(port);int opt = 1;if (setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0)return false;int ret = bind(m_sock, (struct sockaddr*)&svraddr, sizeof(svraddr));if (ret == SOCKET_ERROR) {return false;}return true;}bool ODSocket::Listen(int backlog){int ret = listen(m_sock, backlog);if (ret == SOCKET_ERROR) {return false;}return true;}bool ODSocket::Accept(ODSocket& s, char* fromip){struct sockaddr_in cliaddr;socklen_t addrlen = sizeof(cliaddr);SOCKET sock = accept(m_sock, (struct sockaddr*)&cliaddr, &addrlen);if (sock == SOCKET_ERROR) {return false;}s = sock;if (fromip != NULL)sprintf(fromip, "%s", inet_ntoa(cliaddr.sin_addr));return true;}int ODSocket::Send(const char* buf, int len, int flags){int bytes;int count = 0;while (count < len) {bytes = send(m_sock, buf + count, len - count, flags);if (bytes == -1 || bytes == 0)return -1;count += bytes;}return count;}int ODSocket::Recv(char* buf, int len, int flags){return (recv(m_sock, buf, len, flags));}int ODSocket::Close(){#ifdef WIN32return (closesocket(m_sock));#elsereturn (close(m_sock));#endif}int ODSocket::GetError(){#ifdef WIN32return (WSAGetLastError());#elsereturn (SOCKET_ERROR);#endif}bool ODSocket::DnsParse(const char* domain, char* ip){struct hostent* p;if ((p = gethostbyname(domain)) == NULL)return false;sprintf(ip,"%u.%u.%u.%u",(unsigned char)p->h_addr_list[0][0],(unsigned char)p->h_addr_list[0][1],(unsigned char)p->h_addr_list[0][2],(unsigned char)p->h_addr_list[0][3]);return true;}
三、常见错误:

1、code:blocks编译出错:终端上以root身份创建的文件夹,以other身份(普通用户身份)登录的图形界面,code:blocks是不能在该文件夹中创建工程的,而且打开该文件夹中的文件也是无法成功运行的,因为权限不够。
解决方法:更改文件夹权限,让other用户也有读写执行权限。

chmod 777 SocketDir/
2、客户端connect失败。很有可能是linux防火墙造成的。apache等服务器通信和socket通信都应该先配置好iptables和selinux。初学者也可直接关闭iptables和selinux以方便做测试。
3、绑定(Bind)或者监听(Listen)端口失败。可以利用netstat命令查看绑定的端口状态。
netstat -pan|grep 8889kill -9 2116  //关闭占用该端口的进程






0 0
原创粉丝点击