boost asio广播

一篇boost asio UDP广播示例。

为什么要广播

通常我们需要在局域网来进行广播来查找主机,广播的意思就是向同网段的全部主机发送数据包。而在广域网是不允许的,可以想象广域网主机数量之多,广播造成网络堵塞。广播只能是udp,是由路由器向所有主机发送数据包,包括发送者本身。如果发送的是本身,可以留意下你收的IP:192.168.56.1。还有个组播的,这个在广域网和局域网都允许。

示例代码

服务器:

#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <thread>
void handle_send()
{

};
int main()
{
  namespace ip = boost::asio::ip;
  boost::asio::io_service io_service;

  // Server binds to any address and any port.
  ip::udp::socket socket(io_service,
                         ip::udp::endpoint(ip::udp::v4(), 0));
  socket.set_option(boost::asio::socket_base::broadcast(true));

  // Broadcast will go to port 8888.
  ip::udp::endpoint broadcast_endpoint(ip::address_v4::broadcast(), 8888);

  // Broadcast data.
  boost::array<char, 4> buffer;
 // socket.send_to(boost::asio::buffer(buffer), broadcast_endpoint);
  socket.async_send_to(boost::asio::buffer(buffer), broadcast_endpoint,
	  boost::bind(&handle_send));
  io_service.run();
  //std::thread run_thread([&]{ io_service.run(); });
  //run_thread.join();
}

客户端:

#include <iostream>

#include <boost/asio.hpp>
#include <boost/array.hpp>
int main()
{
  namespace ip = boost::asio::ip;
  boost::asio::io_service io_service;

  // Client binds to any address on port 8888 (the same port on which
  // broadcast data is sent from server).
  ip::udp::socket socket(io_service,
                         ip::udp::endpoint(ip::udp::v4(), 8888 ));

  ip::udp::endpoint sender_endpoint;

  // Receive data.
  boost::array<char, 4> buffer;
  std::size_t bytes_transferred =
    socket.receive_from(boost::asio::buffer(buffer), sender_endpoint);

  std::cout << "remote host ip : " << sender_endpoint.address().to_string() << std::endl;
 // std::cout << "got " << bytes_transferred << " bytes." << std::endl;
}

总结

上面的例子是阻塞模式的广播,有兴趣的可以把它修改成异步模式的,记得udp不是可靠的,上面的例子出处来自国外忘记,,。。。

TrinityCore MMORPG服务器设计分析

本文是通过TrinityCore研究从而对MMORPG服务器设计分析。

网络字节序

ByteBuffer是字节(unsigned char类型)处理,没有大小端处理。在网络通信应用程序上,这种是经常有的,网络是通过字节发送。

消息包格式:包头+包类型+包体

包头rc4加密

登录认证是(srp6)安全远程密码第六版协议,包类型是占一字节。

游戏中,包类型占1.5字节。

1、封包

重载&operator<<
按顺序把数据封包

2、解包

重载&operator>>
按顺序把数据解出

消息包处理

网络是采用boost asio

1、发送

这里需要注意,在这个执行,在多线程里面操作加锁

std::unique_lock<std::mutex> guard(_writeLock);

boost::asio的发送函数:_socket.async_write_some

1.1 登录认证的发送

void AuthSession::SendPacket(ByteBuffer& packet)
{
    if (!IsOpen())
        return;

    if (!packet.empty())
    {
        MessageBuffer buffer;
        buffer.Write(packet.contents(), packet.size());

        std::unique_lock<std::mutex> guard(_writeLock);

        QueuePacket(std::move(buffer), guard);
    }
}

 2.2在游戏中发送

void WorldSocket::SendPacket(WorldPacket const& packet)
{
    if (!IsOpen())
        return;

    if (sPacketLog->CanLogPacket())
        sPacketLog->LogPacket(packet, SERVER_TO_CLIENT, GetRemoteIpAddress(), GetRemotePort());

    ServerPktHeader header(packet.size() + 2, packet.GetOpcode());

    std::unique_lock<std::mutex> guard(_writeLock);

    _authCrypt.EncryptSend(header.header, header.getHeaderLength());

#ifndef TC_SOCKET_USE_IOCP
    if (_writeQueue.empty() && _writeBuffer.GetRemainingSpace() >= header.getHeaderLength() + packet.size())
    {
        _writeBuffer.Write(header.header, header.getHeaderLength());
        if (!packet.empty())
            _writeBuffer.Write(packet.contents(), packet.size());
    }
    else
#endif
    {
        MessageBuffer buffer(header.getHeaderLength() + packet.size());
        buffer.Write(header.header, header.getHeaderLength());
        if (!packet.empty())
            buffer.Write(packet.contents(), packet.size());

        QueuePacket(std::move(buffer), guard);
    }
}

2、接收

接收函数_socket.async_read_some

处理已收到数据包MessageBuffer& packet = GetReadBuffer();

登录认证接收处理:void WorldSocket::ReadHandler()

游戏过程处理:

void WorldSocket::ReadHandler()

bool WorldSocket::ReadHeaderHandler()

bool WorldSocket::ReadDataHandler()

流程

消息通过函数指针映射处理。

1、登录游戏

std::unordered_map<uint8, AuthHandler> const Handlers = AuthSession::InitHandlers();

2、认证通过后

void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)

内部把这次玩家会话添加 :

新建一个会话_worldSession = new WorldSession(id, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter);

添加到世界:sWorld->AddSession(_worldSession);

判断是否有同个帐号登录,如果有,把它踢下线

2、全部会话处理:

void World::UpdateSessions(uint32 diff)
{
..
 for (SessionMap::iterator itr = m_sessions.begin(), next; itr != m_sessions.end(); itr = next)
..

}

2、游戏过程中

extern OpcodeHandler opcodeTable[NUM_MSG_TYPES]

写在后面

TrinityCore常用了TCP通信,tcp通信也是存在心跳的,网络是异常退出(比如,任务管理器直接杀死游戏进程),tcp协议不会通知说我已经退出。如果是实时再线格斗类型游戏,建议常用UDP。TrinityCore大量使用c++ 0x11,有些地方,我也不是明白,如果有存在错误的地方也请指出。

Unity3d 使用boost asio在windows android

本文简单说明Unity3d c++插件,并采用boost asio打开串口设备状态在windows android平台下的交互通信。

Unity3d插件简介

Unity3D底层是c++实现的,用户用c#进行开发,不过是用mono开源,开源的 .NET 开发框架。在实际应用中,我们总有一些代码是其他编程语言实现,历史遗留。插件可以是C、C++、Objective-C等语言实现的。

构建插件

1、插件代码

1、百度云盘:里面有SimplestPluginExample-4.0和boost asio打开串口的例子http://pan.baidu.com/s/1mgy47jU

2、目录jni的MyClass.h是关于boost asio打开串口设备代码

3、下面代码来自官方SimplestPluginExample-4.0

#if _MSC_VER // this is defined when compiling with Visual Studio
#define EXPORT_API __declspec(dllexport) // Visual Studio needs annotating exported functions with this
#else
#define EXPORT_API // XCode does not need annotating exported functions, so define is empty
#endif

// ------------------------------------------------------------------------
// Plugin itself


// Link following functions C-style (required for plugins)
extern "C"
{

// The functions we will call from Unity.
//
const EXPORT_API char*  PrintHello(){
    return "Hello";
}

int EXPORT_API PrintANumber(){
    return 5;
}

int EXPORT_API AddTwoIntegers(int a, int b) {
    return a + b;
}

float EXPORT_API AddTwoFloats(float a, float b) {
    return a + b;
}

} // end of export C block

2、构建Windows插件

打开SimplestPluginExample-4.0SimplestPluginExampleVS2008PluginVisualStudioASimplePlugin.sln

3、构建Android插件

  1. 本机环境windows7
  2. 下载NDK,将Androidandroid-ndk-r9d加到系统环境变量
  3. 进入目录Unity3dPlugin-boostAsioboost-asio
  4. 执行:ndk-build

注意:一定要动态libgnustl_shared.so

 Unity3d插件boost asio应用

1、拷贝库

将编译好的dll和so文件放对应入AssetsPlugins目录下的Android、x86

2、添加到unity3d工程代码

using System.Runtime.InteropServices;
[DllImport("paokunet")]
private static extern void startNet();
[DllImport("paokunet")]
private static extern void stopNet();
[DllImport("paokunet")]
private static extern bool getNetStats();

 3、windows应用

boost库地址:http://sourceforge.net/projects/boost/files/boost-binaries/

没什么好说的

4、安卓应用

  • boost 安卓库 里面有说明编译,如不想看就结尾有现成库。
  • unity3d导出安卓项目记得导出地方对google android打勾
  • boost asio是因动态加载stl才能工作正常

1、添加一个java文件类似这样的

import com.unity3d.player.UnityPlayerActivity;

import android.os.Bundle;
import android.util.Log;

public class OverrideExample extends UnityPlayerNativeActivity {
    static
    {
        //加载.so文件
      Log.d("OverrideActivity", "paokunet freeyun ???????");
      {
          System.loadLibrary("gnustl_shared");
          System.loadLibrary("paokunet");
       }
    }
}

2、AndroidManifest.xml类似这样

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.Unity3d.u3d" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
  <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" />
  <application android:theme="@android:style/Theme.NoTitleBar" android:icon="@drawable/app_icon" android:label="@string/app_name" >
    <activity android:label="@string/app_name" android:screenOrientation="landscape" android:launchMode="singleTask" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale" android:name="com.hj.u3d.OverrideExample">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
      </intent-filter>
      <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
      <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="false" />
    </activity>
  </application>
  <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="22" />
  <uses-feature android:glEsVersion="0x00020000" />
  <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
  <uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false" />
  <uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="false" />
</manifest>

 总结

只是用用boost aiso串口代码,注意串口的设备打开是不一样的,安卓和Linux设备类似“”/dev/ttyS1”,windows类“COM8”如果需要用tcp udp通信也是可以的。

android编译boost库

本文描述在Debian 8.0系统,Android NDK编译android版本的boost库,最后给出使用Android.mk及已编译好的库。

预备

andorod NDK版本:最高去到r10d目前最新的,建议android-ndk-r9d 支持的boost版本:1.45.0、1.48.0、1.49.0、1.53.0、1.54.0、1.55.0。

Boost-for-Android: https://github.com/MysticTreeGames/Boost-for-Android/archive/master.zip

编译boost库

如果不想编译就直接跳过,后面给出已经编译好的boost库

  1. 终端下执行sudo apt-get install ia32-libs,x64位缺少,请按提示安装。
  2. 配置环境变量:$(NDK_ROOT) ,依次执行:
    • export NDK_ROOT=/usr/local/src/android-ndk-r9d
    • export PATH=$NDK_ROOT:$PATH
  3. 修改build-android.sh的内容
    1.  --layout=versioned
       #增加下面两行
       --without-python
       --without-locale
       #增加结束
       -sICONV_PATH=`pwd`/../libiconv-libicu-android/armeabi 
  4. 终端执行: ./build-android.sh $(NDK_ROOT)

boost库的使用

1.你的程序Application.mk

APP_STL := gnustl_static
APP_CPPFLAGS += -frtti -fexceptions

boost库的编译是用指定了gnustl的标准库。

2.你的程序Android.mk

#导入boost库所有在的目录
$(call import-add-path,$(LOCAL_PATH)/../../../../build)
..
..
LOCAL_WHOLE_STATIC_LIBRARIES += boost_static
include $(BUILD_STATIC_LIBRARY)
$(call import-module,boost)

3.boost 库的Android.mk文件内容

LOCAL_PATH:= $(call my-dir)
# boost_date_time
#
include $(CLEAR_VARS)
LOCAL_MODULE := boost_date_time
LOCAL_SRC_FILES := lib/libboost_date_time-gcc-mt-1_55.a
include $(PREBUILT_STATIC_LIBRARY)

# boost_filesystem
#
include $(CLEAR_VARS)
LOCAL_MODULE := boost_filesystem
LOCAL_SRC_FILES := lib/libboost_filesystem-gcc-mt-1_55.a
include $(PREBUILT_STATIC_LIBRARY)

# boost_thread
#
include $(CLEAR_VARS)
LOCAL_MODULE := boost_thread
LOCAL_SRC_FILES := lib/libboost_thread-gcc-mt-1_55.a
include $(PREBUILT_STATIC_LIBRARY)

# boost_system
#
include $(CLEAR_VARS)
LOCAL_MODULE := boost_system
LOCAL_SRC_FILES := lib/libboost_system-gcc-mt-1_55.a
include $(PREBUILT_STATIC_LIBRARY)

# boost_program_options
#
include $(CLEAR_VARS)
LOCAL_MODULE := boost_program_options
LOCAL_SRC_FILES := lib/libboost_program_options-gcc-mt-1_55.a
include $(PREBUILT_STATIC_LIBRARY)

# boost_chrono
#
#include $(CLEAR_VARS)
#LOCAL_MODULE := boost_chrono
#LOCAL_SRC_FILES := lib/libboost_chrono-gcc-mt-1_55.a
#include $(PREBUILT_STATIC_LIBRARY)

# first lib, which will be built statically
#
include $(CLEAR_VARS)
LOCAL_MODULE := boost_static
LOCAL_MODULE_FILENAME := boost
LOCAL_STATIC_LIBRARIES := boost_date_time
                          boost_system
                          boost_filesystem
                          boost_program_options
                          boost_thread
                         # boost_chrono
#LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/boost-1_55
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include/boost-1_55
#LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes
include $(BUILD_STATIC_LIBRARY)

 编译好的boost 1.55的下载

build ndk-r9d-boost1.55.0:http://pan.baidu.com/s/1pJKH6gr