cocos2dx长连接BSDSocke网络通信

一、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 object
	auto scene = Scene::create();

	// 'layer' is an autorelease object
	auto layer = HelloWorld::create();

	// add layer as a child to scene
	scene->addChild(layer);

	// return the scene
	return 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 screen
	pLabel->setPosition(ccp(origin.x + visibleSize.width / 2,
		origin.y + visibleSize.height - pLabel->getContentSize().height));

	//add the label as a child to this layer
	this->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 int				socklen_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 int				SOCKET;

//#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 data
	bool Create(int af, int type, int protocol = 0);

	// Connect socket
	bool Connect(const string ip, unsigned short port);
	//#region server
	// Bind socket
	bool Bind(unsigned short port);

	// Listen socket
	bool Listen(int backlog = 5);

	// Accept socket
	bool Accept(ODSocket& s, char* fromip = NULL);
	//#endregion

	// Send socket
	int Send(const char* buf, int len, int flags = 0);

	// Recv socket
	int Recv(char* buf, int len, int flags = 0);

	// Close socket
	int Close();

	// Get errno
	int GetError();

	//#pragma region just for win32
	// Init winsock DLL 
	static int Init();
	// Clean winsock DLL
	static int Clean();
	//#pragma endregion

	// Domain parse
	static 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")
#endif


ODSocket::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).aspx

	typedef struct WSAData {
	WORD wVersion;		//winsock version
	WORD wHighVersion;	//The highest version of the Windows Sockets specification that the Ws2_32.dll can support
	char 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 up
	if (ret) {
		//cerr << "Initilize winsock error !" << endl;
		return -1;
	}
#endif

	return 0;
}
//this is just for windows
int ODSocket::Clean()
{
#ifdef WIN32
	return (WSACleanup());
#endif
	return 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 server
bool 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 WIN32
	return (closesocket(m_sock));
#else
	return (close(m_sock));
#endif
}

int ODSocket::GetError()
{
#ifdef WIN32
	return (WSAGetLastError());
#else
	return (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 8889
kill -9 2116  //关闭占用该端口的进程






  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值