使用 C++ 创建 UDP 服务器以嵌入跨平台 iOS 和 Android 应用程序
Create UDP server using C++ to embed in cross platform iOS and Android app
我正在使用 cocos2d-x 开发一款跨平台手机游戏(iOS 和 Android)。
我的大部分代码是用 C++ 编写的,OS 特定代码在 Objective-C / Java / Swift 中使用桥接器。
我想知道是否有人使用任何 C++ 库在他们的应用程序中托管 UDP 服务器?
编辑:到目前为止,我已经找到了许多特定于平台的解决方案(对 Android 使用 Java,对 iOS 使用 cocoaasync 等),但在 C++ 中没有特别使用过的解决方案对于跨平台应用程序。
编辑:我更喜欢没有提升的解决方案。最好包含一些简单的内容,例如向项目中添加几个文件。
您最有可能使用 Valve 的 GameNetworkingSockets,https://github.com/ValveSoftware/GameNetworkingSockets
它们的外部依赖性非常有限,因此您应该能够为 iOS 和 Android
编译它们
您还可以查看此列表:https://github.com/MFatihMAR/Awesome-Game-Networking,其中有一个库列表,您可以选择尝试。
您可以在这种类型的项目 (Android/iOS) 中使用 ASIO Standalone library. It is the same library available as boost/asio, but it doesn't require any other boost libraries. I have used boost/asio,它是迄今为止最好的解决方案。
这是我最终得到的结果:
h 文件:
#include "Queue.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <array>
#include <iostream>
#include <thread>
using namespace std;
#define MAXBUFFER_SIZE 1024
class UDPServer {
public:
/**
* Constructor
*
* @port the port on which the UDP server is listening for packets.
*/
explicit UDPServer(unsigned short port);
/**
* Destructor
*/
~UDPServer() = default;
/**
* Setup the server.
*/
void setupServer();
/**
* Get a single message.
* For demonstration purposes, our messages is expected to be a array of int
*/
bool getMessage(std::array<int, 4>& message);
bool getIPAddress(std::array<int, 4>& message);
void setFoundIP();
bool isReady();
void nextPort();
int getPort();
private:
bool _isBoundToPort = false;
/**
* The server port.
*/
unsigned short port_;
bool isFoundIP = false;
/**
* The thread-safe message queue.
*/
Queue queue_;
Queue _ipAddresses;
/**
* The UDP server function.
*/
int UDPServerFunc();
};
cpp 文件:
#include "UDPServer.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
/**
* This function parses an incoming message with the following format: 1;234;-89;-53;
*
* A valid message consists of 4 integer values separated by semicolons.
*/
inline std::array<int, 4> parseMessage(const std::string& input);
inline std::array<int,4> parseIp(const std::string& input);
UDPServer::UDPServer(unsigned short port) {
port_ = port;
}
bool UDPServer::getMessage(std::array<int, 4>& message) {
return queue_.pop(message);
}
bool UDPServer::getIPAddress(std::array<int, 4>& message) {
return _ipAddresses.pop(message);
}
void UDPServer::setFoundIP(){
isFoundIP = true;
}
bool UDPServer::isReady(){
return _isBoundToPort;
}
void UDPServer::nextPort(){
port_++;
}
int UDPServer::getPort(){
return port_;
}
void UDPServer::setupServer() {
// Launch the server thread.
std::thread t([this](){
UDPServerFunc();
});
t.detach();
}
int UDPServer::UDPServerFunc() {
// Creating socket file descriptor
int sockfd;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// Filling server information
struct sockaddr_in servaddr, cliaddr;
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
servaddr.sin_family = AF_INET; // IPv
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(port_);
// Bind the socket with the server address
if (::bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
_isBoundToPort = true;
while (true) {
// Read the next message from the socket.
char message[MAXBUFFER_SIZE];
socklen_t len = sizeof(struct sockaddr);
ssize_t n = recvfrom(sockfd, (char *)&message, MAXBUFFER_SIZE, MSG_DONTWAIT,
(struct sockaddr *)&cliaddr, (socklen_t*)&len);
if (n > 0) {
message[n] = '[=11=]';
// Parse incoming data and push the result on the queue.
// Parsed messages are represented as a std::array<int, 4>.
if(!isFoundIP){
_ipAddresses.push(parseIp(message));
}else{
queue_.push(parseMessage(message));
}
} else {
// Wait a fraction of a millisecond for the next message.
usleep(100);
}
}
return 0;
}
我从我的答案中删除了所有不必要的代码,因为真正的内容就是上面的代码。如果有人也需要额外的功能,我在 Github 上分享了代码,稍后也会添加一些示例。
上面的代码非常简单,有几个解析函数用于提取 IP 地址,或者一组由分号分隔的四个数字。上面的代码很简单,自己修改自己的自定义消息。
Queue.h只是一个简单的线程安全队列。
我正在使用 cocos2d-x 开发一款跨平台手机游戏(iOS 和 Android)。 我的大部分代码是用 C++ 编写的,OS 特定代码在 Objective-C / Java / Swift 中使用桥接器。
我想知道是否有人使用任何 C++ 库在他们的应用程序中托管 UDP 服务器?
编辑:到目前为止,我已经找到了许多特定于平台的解决方案(对 Android 使用 Java,对 iOS 使用 cocoaasync 等),但在 C++ 中没有特别使用过的解决方案对于跨平台应用程序。
编辑:我更喜欢没有提升的解决方案。最好包含一些简单的内容,例如向项目中添加几个文件。
您最有可能使用 Valve 的 GameNetworkingSockets,https://github.com/ValveSoftware/GameNetworkingSockets
它们的外部依赖性非常有限,因此您应该能够为 iOS 和 Android
编译它们您还可以查看此列表:https://github.com/MFatihMAR/Awesome-Game-Networking,其中有一个库列表,您可以选择尝试。
您可以在这种类型的项目 (Android/iOS) 中使用 ASIO Standalone library. It is the same library available as boost/asio, but it doesn't require any other boost libraries. I have used boost/asio,它是迄今为止最好的解决方案。
这是我最终得到的结果:
h 文件:
#include "Queue.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <array>
#include <iostream>
#include <thread>
using namespace std;
#define MAXBUFFER_SIZE 1024
class UDPServer {
public:
/**
* Constructor
*
* @port the port on which the UDP server is listening for packets.
*/
explicit UDPServer(unsigned short port);
/**
* Destructor
*/
~UDPServer() = default;
/**
* Setup the server.
*/
void setupServer();
/**
* Get a single message.
* For demonstration purposes, our messages is expected to be a array of int
*/
bool getMessage(std::array<int, 4>& message);
bool getIPAddress(std::array<int, 4>& message);
void setFoundIP();
bool isReady();
void nextPort();
int getPort();
private:
bool _isBoundToPort = false;
/**
* The server port.
*/
unsigned short port_;
bool isFoundIP = false;
/**
* The thread-safe message queue.
*/
Queue queue_;
Queue _ipAddresses;
/**
* The UDP server function.
*/
int UDPServerFunc();
};
cpp 文件:
#include "UDPServer.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
using namespace std;
/**
* This function parses an incoming message with the following format: 1;234;-89;-53;
*
* A valid message consists of 4 integer values separated by semicolons.
*/
inline std::array<int, 4> parseMessage(const std::string& input);
inline std::array<int,4> parseIp(const std::string& input);
UDPServer::UDPServer(unsigned short port) {
port_ = port;
}
bool UDPServer::getMessage(std::array<int, 4>& message) {
return queue_.pop(message);
}
bool UDPServer::getIPAddress(std::array<int, 4>& message) {
return _ipAddresses.pop(message);
}
void UDPServer::setFoundIP(){
isFoundIP = true;
}
bool UDPServer::isReady(){
return _isBoundToPort;
}
void UDPServer::nextPort(){
port_++;
}
int UDPServer::getPort(){
return port_;
}
void UDPServer::setupServer() {
// Launch the server thread.
std::thread t([this](){
UDPServerFunc();
});
t.detach();
}
int UDPServer::UDPServerFunc() {
// Creating socket file descriptor
int sockfd;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// Filling server information
struct sockaddr_in servaddr, cliaddr;
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
servaddr.sin_family = AF_INET; // IPv
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(port_);
// Bind the socket with the server address
if (::bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
_isBoundToPort = true;
while (true) {
// Read the next message from the socket.
char message[MAXBUFFER_SIZE];
socklen_t len = sizeof(struct sockaddr);
ssize_t n = recvfrom(sockfd, (char *)&message, MAXBUFFER_SIZE, MSG_DONTWAIT,
(struct sockaddr *)&cliaddr, (socklen_t*)&len);
if (n > 0) {
message[n] = '[=11=]';
// Parse incoming data and push the result on the queue.
// Parsed messages are represented as a std::array<int, 4>.
if(!isFoundIP){
_ipAddresses.push(parseIp(message));
}else{
queue_.push(parseMessage(message));
}
} else {
// Wait a fraction of a millisecond for the next message.
usleep(100);
}
}
return 0;
}
我从我的答案中删除了所有不必要的代码,因为真正的内容就是上面的代码。如果有人也需要额外的功能,我在 Github 上分享了代码,稍后也会添加一些示例。
上面的代码非常简单,有几个解析函数用于提取 IP 地址,或者一组由分号分隔的四个数字。上面的代码很简单,自己修改自己的自定义消息。
Queue.h只是一个简单的线程安全队列。