做网络游戏的时候,我们肯定不能使用http进行数据的交换,下面纪录下cocos2d-x使用socket的方法
客户端用的是ODSocket,服务端研究半天,最后还是发现java做socket服务端比C++要方便太多。
下面是cocos2d客户端文件目录结构
下面是java服务端文件目录结构
接下来直接上代码,代码中有详细的注释
首先是客户端
HelloWorldScene.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
#include "ODSocket/ODSocket.h"
class HelloWorld : public cocos2d::Layer
{
public:
static cocos2d::Scene* createScene();
virtual bool init();
CREATE_FUNC(HelloWorld);
void connectServer();
void receiveData();
private:
ODSocket socket;
};
#endif // __HELLOWORLD_SCENE_H__
HelloWorldScene.cpp
#include "HelloWorldScene.h"
USING_NS_CC;
Scene* HelloWorld::createScene()
{
auto scene = Scene::create();
auto layer = HelloWorld::create();
scene->addChild(layer);
return scene;
}
bool HelloWorld::init()
{
if ( !Layer::init() )
{
return false;
}
// cocos2d::Size visibleSize = Director::getInstance()->getVisibleSize();
// Vec2 origin = Director::getInstance()->getVisibleOrigin();
this->connectServer();
return true;
}
// Socker连接
void HelloWorld::connectServer()
{
// 初始化
socket.Init();
socket.Create(AF_INET, SOCK_STREAM, 0);
// 设置服务器的IP地址,端口号
// 并连接服务器 Connect
const char* ip = "127.0.0.1";
int port = 12345;
bool result = socket.Connect(ip, port);
// 发送数据 Send
std::string data = "我连接上了";
socket.Send(Value(data).asString().c_str(), (int)strlen(Value(data).asString().c_str()));
if (result) {
CCLOG("连接服务器成功!");
// 开启新线程,在子线程中,接收数据
std::thread recvThread = std::thread(&HelloWorld::receiveData, this);
recvThread.detach(); // 从主线程分离
}
else {
CCLOG("无法连接服务器!");
return;
}
}
// 接收数据
void HelloWorld::receiveData()
{
// 因为是强联网
// 所以可以一直检测服务端是否有数据传来
while (true) {
// 接收数据 Recv
char data[512] = "";
int result = socket.Recv(data, 512, 0);
// 与服务器的连接断开了
if (result <= 0) {
CCLOG("服务器已经断开连接!");
break;
}
CCLOG("%s", data);
std::string str = "我收到了你的消息" + Value(data).asString();
socket.Send(Value(str).asString().c_str(), (int)strlen(Value(str).asString().c_str()));
}
// 关闭连接
socket.Close();
}
接下来是服务端
Main.java
package com.ron.socket;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Main {
public static void main(String[] args) {
// 创建ServerSocket,监听端口号:12345
ServerSocket ss;
try {
ss = new ServerSocket(12345);
// 创建用于管理客户端的收发数据的子线程类
ClientThread clientThread = new ClientThread();
clientThread.start();
System.out.println("服务器开启啦");
// 监听端口号:12345
// 等待客户连接 accept()
while (true) {
// 开始接收客户端的连接
Socket socket = ss.accept();
System.out.println("有新客户连接~");
clientThread.addClient(socket);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
ClientThread.java
package com.ron.socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
//继承Thread线程类
public class ClientThread extends Thread {
// 客户端连接的socket列表
private ArrayList<Socket> clients = new ArrayList<Socket>();
// 添加客户
public void addClient(Socket socket) {
clients.add(socket);
}
// 删除客户
public void removeClient(Socket socket) {
clients.remove(socket);
}
// 向客户发送数据
public void sendMessage(Socket socket, String data) throws IOException {
// 给玩家发送数据
OutputStream os = socket.getOutputStream();
os.write(data.getBytes("UTF-8"));
}
@Override
public void run() {
while (true) {
try {
for (Socket socket : clients) {
// 获取客户端发来的数据
InputStream is = socket.getInputStream();
int len = is.available() + 1;
byte[] buff = new byte[len];
int flag = is.read(buff);
// read()返回-1,说明客户端的socket已断开
if (flag == -1) {
System.out.println("客户已经断开连接~");
this.removeClient(socket);
break;
}
// 输出接收到的数据
String read = new String(buff);
System.out.println("收到数据:" + read);
// 给玩家发送数据
String data = "恭喜你,连接成功啦~~";
sendMessage(socket, data);
}
sleep(10);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
首先运行服务端,然后运行客户端。服务端需要Run As Java Application。运行成功后,会看到服务端和客户端在不断的通信
接下来是ODSocket的代码,http://www.codeforge.cn/read/214931/ODSocket.h__html这里有下载,不过下面我也贴上来好了。
ODSocket.cpp
#include "ODSocket.h"
#ifdef WIN32
#include "StdAfx.h"
#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 char* ip, unsigned short port)
{
struct sockaddr_in svraddr;
svraddr.sin_family = AF_INET;
svraddr.sin_addr.s_addr = inet_addr(ip);
svraddr.sin_port = htons(port);
int ret = connect(m_sock, (struct sockaddr*)&svraddr, sizeof(svraddr));
if ( ret == SOCKET_ERROR ) {
return false;
}
return true;
}
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;
}
//for server
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 (0);
#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;
}
ODSocket.h
/*
* define file about portable socket class.
* description:this sock is suit both windows and linux
* design:odison
* e-mail:odison@126.com>
*
*/
#ifndef _ODSOCKET_H_
#define _ODSOCKET_H_
#ifdef WIN32
#include <winsock.h>
typedef int socklen_t;
#else
#include "cocos2d.h"
#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
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 char* 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 ();
protected:
SOCKET m_sock;
};
#endif
stdafx.cpp
// stdafx.cpp : source file that includes just the standard includes
// ChatClient.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file
stdafx.h
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#include <stdio.h>
//#include <tchar.h>
// TODO: reference additional headers your program requires here
targetver.h
#pragma once
// The following macros define the minimum required platform. The minimum required platform
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
// your application. The macros work by enabling all features available on platform versions up to and
// including the version specified.
// Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif
tchar.h
/***
*tchar.h - definitions for generic international text functions
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* Definitions for generic international functions, mostly defines
* which map string/formatted-io/ctype functions to char, wchar_t, or
* MBCS versions. To be used for compatibility between single-byte,
* multi-byte and Unicode text models.
*
* [Public]
*
****/
#pragma once
#include <crtdefs.h>
#ifndef _INC_TCHAR
#define _INC_TCHAR
#ifdef _STRSAFE_H_INCLUDED_
#error Need to include strsafe.h after tchar.h
#endif
#pragma warning(disable:4514) /* disable unwanted C++ /W4 warning */
/* #pragma warning(default:4514) */ /* use this to reenable, if necessary */
/* Notes */
/* There is no:
* _tcscat_l
* _tcscpy_l
* because mbscat and mbscpy just behave like strcat and strcpy,
* so no special locale-specific behavior is needed.
*/
/* Functions like:
* _strncat_l
* _strncat_s_l
* are only available if ANSI is defined (i.e. no _UNICODE nor _MBCS),
* because these functions are only accessible through the _tcs macros.
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _CRT_FAR_MAPPINGS_NO_DEPRECATE
/*
Long ago, these f prefix text functions referred to handling of text in segmented architectures. Ever since the move
to Win32 they have been obsolete names, but we kept them around as aliases. Now that we have a deprecation
mechanism we can warn about them. You should switch to the identical function without the f prefix.
*/
#pragma deprecated("_ftcscat")
#pragma deprecated("_ftcschr")
#pragma deprecated("_ftcscpy")
#pragma deprecated("_ftcscspn")
#pragma deprecated("_ftcslen")
#pragma deprecated("_ftcsncat")
#pragma deprecated("_ftcsncpy")
#pragma deprecated("_ftcspbrk")
#pragma deprecated("_ftcsrchr")
#pragma deprecated("_ftcsspn")
#pragma deprecated("_ftcsstr")
#pragma deprecated("_ftcstok")
#pragma deprecated("_ftcsdup")
#pragma deprecated("_ftcsnset")
#pragma deprecated("_ftcsrev")
#pragma deprecated("_ftcsset")
#pragma deprecated("_ftcscmp")
#pragma deprecated("_ftcsicmp")
#pragma deprecated("_ftcsnccmp")
#pragma deprecated("_ftcsncmp")
#pragma deprecated("_ftcsncicmp")
#pragma deprecated("_ftcsnicmp")
#pragma deprecated("_ftcscoll")
#pragma deprecated("_ftcsicoll")
#pragma deprecated("_ftcsnccoll")
#pragma deprecated("_ftcsncoll")
#pragma deprecated("_ftcsncicoll")
#pragma deprecated("_ftcsnicoll")
#pragma deprecated("_ftcsclen")
#pragma deprecated("_ftcsnccat")
#pragma deprecated("_ftcsnccpy")
#pragma deprecated("_ftcsncset")
#pragma deprecated("_ftcsdec")
#pragma deprecated("_ftcsinc")
#pragma deprecated("_ftcsnbcnt")
#pragma deprecated("_ftcsnccnt")
#pragma deprecated("_ftcsnextc")
#pragma deprecated("_ftcsninc")
#pragma deprecated("_ftcsspnp")
#pragma deprecated("_ftcslwr")
#pragma deprecated("_ftcsupr")
#pragma deprecated("_ftclen")
#pragma deprecated("_ftccpy")
#pragma deprecated("_ftccmp")
#endif /* ndef _CRT_FAR_MAPPINGS_NO_DEPRECATE */
#define _ftcscat _tcscat
#define _ftcschr _tcschr
#define _ftcscpy _tcscpy
#define _ftcscspn _tcscspn
#define _ftcslen _tcslen
#define _ftcsncat _tcsncat
#define _ftcsncpy _tcsncpy
#define _ftcspbrk _tcspbrk
#define _ftcsrchr _tcsrchr
#define _ftcsspn _tcsspn
#define _ftcsstr _tcsstr
#define _ftcstok _tcstok
#define _ftcsdup _tcsdup
#define _ftcsnset _tcsnset
#define _ftcsrev _tcsrev
#define _ftcsset _tcsset
#define _ftcscmp _tcscmp
#define _ftcsicmp _tcsicmp
#define _ftcsnccmp _tcsnccmp
#define _ftcsncmp _tcsncmp
#define _ftcsncicmp _tcsncicmp
#define _ftcsnicmp _tcsnicmp
#define _ftcscoll _tcscoll
#define _ftcsicoll _tcsicoll
#define _ftcsnccoll _tcsnccoll
#define _ftcsncoll _tcsncoll
#define _ftcsncicoll _tcsncicoll
#define _ftcsnicoll _tcsnicoll
/* Redundant "logical-character" mappings */
#define _ftcsclen _tcsclen
#define _ftcsnccat _tcsnccat
#define _ftcsnccpy _tcsnccpy
#define _ftcsncset _tcsncset
#define _ftcsdec _tcsdec
#define _ftcsinc _tcsinc
#define _ftcsnbcnt _tcsnbcnt
#define _ftcsnccnt _tcsnccnt
#define _ftcsnextc _tcsnextc
#define _ftcsninc _tcsninc
#define _ftcsspnp _tcsspnp
#define _ftcslwr _tcslwr
#define _ftcsupr _tcsupr
#define _ftclen _tclen
#define _ftccpy _tccpy
#define _ftccmp _tccmp
#ifndef _CONST_RETURN
#ifdef __cplusplus
#define _CONST_RETURN const
#define _CRT_CONST_CORRECT_OVERLOADS
#else
#define _CONST_RETURN
#endif
#endif
/* For backwards compatibility */
#define _WConst_return _CONST_RETURN
#ifdef _UNICODE
#ifdef __cplusplus
} /* ... extern "C" */
#endif
/* ++++++++++++++++++++ UNICODE ++++++++++++++++++++ */
#include <wchar.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _WCTYPE_T_DEFINED
typedef unsigned short wint_t;
typedef unsigned short wctype_t;
#define _WCTYPE_T_DEFINED
#endif
#ifndef __TCHAR_DEFINED
typedef wchar_t _TCHAR;
typedef wchar_t _TSCHAR;
typedef wchar_t _TUCHAR;
typedef wchar_t _TXCHAR;
typedef wint_t _TINT;
#define __TCHAR_DEFINED
#endif
#ifndef _TCHAR_DEFINED
#if !__STDC__
typedef wchar_t TCHAR;
#endif
#define _TCHAR_DEFINED
#endif
#define _TEOF WEOF
#define __T(x) L ## x
/* Program */
#define _tmain wmain
#define _tWinMain wWinMain
#define _tenviron _wenviron
#define __targv __wargv
/* Formatted i/o */
#define _tprintf wprintf
#define _tprintf_l _wprintf_l
#define _tprintf_s wprintf_s
#define _tprintf_s_l _wprintf_s_l
#define _tprintf_p _wprintf_p
#define _tprintf_p_l _wprintf_p_l
#define _tcprintf _cwprintf
#define _tcprintf_l _cwprintf_l
#define _tcprintf_s _cwprintf_s
#define _tcprintf_s_l _cwprintf_s_l
#define _tcprintf_p _cwprintf_p
#define _tcprintf_p_l _cwprintf_p_l
#define _vtcprintf _vcwprintf
#define _vtcprintf_l _vcwprintf_l
#define _vtcprintf_s _vcwprintf_s
#define _vtcprintf_s_l _vcwprintf_s_l
#define _vtcprintf_p _vcwprintf_p
#define _vtcprintf_p_l _vcwprintf_p_l
#define _ftprintf fwprintf
#define _ftprintf_l _fwprintf_l
#define _ftprintf_s fwprintf_s
#define _ftprintf_s_l _fwprintf_s_l
#define _ftprintf_p _fwprintf_p
#define _ftprintf_p_l _fwprintf_p_l
#define _stprintf _swprintf
#define _stprintf_l __swprintf_l
#define _stprintf_s swprintf_s
#define _stprintf_s_l _swprintf_s_l
#define _stprintf_p _swprintf_p
#define _stprintf_p_l _swprintf_p_l
#define _sctprintf _scwprintf
#define _sctprintf_l _scwprintf_l
#define _sctprintf_p _scwprintf_p
#define _sctprintf_p_l _scwprintf_p_l
#define _sntprintf _snwprintf
#define _sntprintf_l _snwprintf_l
#define _sntprintf_s _snwprintf_s
#define _sntprintf_s_l _snwprintf_s_l
#define _vtprintf vwprintf
#define _vtprintf_l _vwprintf_l
#define _vtprintf_s vwprintf_s
#define _vtprintf_s_l _vwprintf_s_l
#define _vtprintf_p _vwprintf_p
#define _vtprintf_p_l _vwprintf_p_l
#define _vftprintf vfwprintf
#define _vftprintf_l _vfwprintf_l
#define _vftprintf_s vfwprintf_s
#define _vftprintf_s_l _vfwprintf_s_l
#define _vftprintf_p _vfwprintf_p
#define _vftprintf_p_l _vfwprintf_p_l
#define _vstprintf vswprintf
#define _vstprintf_l _vswprintf_l
#define _vstprintf_s vswprintf_s
#define _vstprintf_s_l _vswprintf_s_l
#define _vstprintf_p _vswprintf_p
#define _vstprintf_p_l _vswprintf_p_l
#define _vsctprintf _vscwprintf
#define _vsctprintf_l _vscwprintf_l
#define _vsctprintf_p _vscwprintf_p
#define _vsctprintf_p_l _vscwprintf_p_l
#define _vsntprintf _vsnwprintf
#define _vsntprintf_l _vsnwprintf_l
#define _vsntprintf_s _vsnwprintf_s
#define _vsntprintf_s_l _vsnwprintf_s_l
#define _tscanf wscanf
#define _tscanf_l _wscanf_l
#define _tscanf_s wscanf_s
#define _tscanf_s_l _wscanf_s_l
#define _tcscanf _cwscanf
#define _tcscanf_l _cwsca