VxWorks6.6移植嵌入式ICE中间件解决方案


一、前言

         iceE1.3.0中间件当前版本并没有直接支持VxWorks,我们可能在百度搜索上也找不到相关移植资料。在Windows,unix,linux等相关操作系统下,也许你可以轻松地搞定。或许估计你曾经尝试把它移植到VxWorks实时操作系统,其过程估计没有想象那么容易,只有身临其中才能有所体验了。

         在Ice移植VxWorks过程中,我们需要定义宏“VXWORKS”开关。VxWorks底层网络遵循POSIX标准,但不同的操作系统中POSIX还是有一点差异,代码修改过程中使用VXWORKS标志区别出来。

         本文基于VxWorks本身的仿真器实现,完成ice的动态库创建,并使用最简单的例子“Hello World!”实现客服与服务器之间的通信。

让我们开始进入正式的主题吧!

二、了解POISX标准

        POSIX具有多重含义,通常指POSIX标准,该标准是一个可移植操作系统接口(Portable OperatingSystem Interface),由IEEE提出,ANSI和ISO将其标准化。POSIX的目的是使应用程序源代码可以在兼容POSIX的操作系统上移植。理想的目标是应用程序移植到另一个操作系统只需要重新编译就可以运行。POSIX最后一个字母“X”表达了这种超乎操作系统差异的理想。目前并没有实现这种理想:从操作系统看,由于目标、要求、理念、条件的差异,并不是所有的操作系统都实现100%POSIX兼容;从应用程序看,很多代码编写使用了特定操作系统支持的调用,并没有很好地使用POSIX接口。但是,很显然,使用POSIX接口的应用程序在兼容POSIX的操作系统间移植将是很轻松的事情。

        POSIX标准是一个处于不断发展之中的庞大体系,包括:

1003.1       系统API

1003.2       SHELL及工具

1003.3       POSIX符合性测试方法

1003.5      ADA语言接口

1003.13      标准化可移植实时应用环境AEP

        其中,POSIX 1003.1系列标准是POSIX最主体内容,也是我们最关心的部分。该系列内容由如下主体定义以及一些扩展和增补组成:

1003.1       1988年通过,基本OS接口

1003.1b     1993年通过,实时扩展

1003.1c      1995年通过,线程扩展

1003.1d     1999年通过,实时扩展

1003.1j      2000年通过,高级实时扩展

1003.1q     2000年通过,事件数据流跟踪

三、测试POISX线程相关的函数


图3.1 创建RTP工程


图3.2 选择编译器

1、编写一个测试代码testpoisx.cpp

#include <stdio.h>

#include <pthread.h>

#include <errno.h>

#include <semLib.h>

 

typedef void* (*LPFUNCPTR)(void*);

   

struct counter

{

    int i;

    int j;

};

 

static bool __running =true;

static counter __counter = { 0, 0 };

pthread_mutex_t __mutex;

 

static void*

task1(void* arg)

{

    struct timespec ts;

   while(__running)

    {

       int rc = pthread_mutex_lock(&__mutex);          

       printf("Currentcounter i:%d\n", __counter.i++);       

       rc =pthread_mutex_unlock(&__mutex);       

  

       ts.tv_sec = 1;

       ts.tv_nsec = 0;

       nanosleep(&ts, 0);

    }

   return 0;

}

 

static void*

task2(void* arg)

{

    struct timespec ts;

   while(__running)

    {

       int rc = pthread_mutex_lock(&__mutex);          

       printf("Currentcounter j:%d\n", __counter.j++);       

       rc =pthread_mutex_unlock(&__mutex);       

       ts.tv_sec = 2;

       ts.tv_nsec = 0;

       nanosleep(&ts, 0);

    }

   return 0;

}

 

int

startTask(LPFUNCPTR func,

          size_t stackSize,

          const bool& realtimeScheduling,

          const int& priority)

{

    pthread_tid;

   pthread_attr_t attr;

    int rc = pthread_attr_init(&attr);

    if (rc != 0)

    {

        return -1;

    }

    if (stackSize > 0)

    {

        if(stackSize < PTHREAD_STACK_MIN)

        {

           stackSize = PTHREAD_STACK_MIN;

        }

        rc= pthread_attr_setstacksize(&attr, stackSize);

        if (rc != 0)

        {

           return -1;

        }

    }

 

    if (realtimeScheduling)

    {

        rc= pthread_attr_setschedpolicy(&attr, SCHED_RR);

        if (rc != 0)

        {

           return -1;

        }

       sched_param param;

       param.sched_priority = priority;

        rc= pthread_attr_setschedparam(&attr, &param);

        if (rc != 0)

        {

            return -1;

        }

       pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);

    }

    rc =pthread_create(&id, &attr, func, NULL);

    if (rc != 0)

    {

        return -1;

    }

    return id;

}

 

int

stopTask(constpthread_t& id)

{

    int rc = pthread_detach(id);

    return rc;

}

 

int

main(int argc, char* argv[])

{      

    int rc = pthread_mutex_init(&__mutex, 0);

    if (rc != 0)

    {

        return -1;

    }

    int nId1 = startTask((LPFUNCPTR)task1, 4096,true, 100);

    int nId2 = startTask((LPFUNCPTR)task2, 4096,true, 100);

   

    while (__running)

    {

        if (getchar() == '\n')

        {

            __running= false;

            break;

        }

    }

    struct timespec ts;

    ts.tv_sec= 2;

    ts.tv_nsec= 0;

    nanosleep(&ts,0);

   

    if (nId1 > 0)

    {

       stopTask(nId1);

    }

    if (nId2 > 0)

    {

       stopTask(nId2);

    }

   

    rc =pthread_mutex_destroy(&__mutex);

    if (rc != 0)

    {

        return -1;

    }

    return 0;

}

2、运行测试代码


图3.3 选择vxsim0仿真


图3.4 运行之后的结果

当程序代码执行pthread_create时,返回结果始终为“-1”,这里你必须对VxWorks的POSIX过程要熟悉了。经过查询有关错误代码资料(#define        ENOSYS             71              /*Function not implemented */),我们发现VxWorks提供的仿真器功能很基础,但有很多组件未包含进来,于是我们需要定制自己的镜像文件,详细过程参考图5.8-5.9。


图3.5 两条任务线程启动

Current counter i:0

Current counter j:0

Current counter i:1

Current counter j:1

Current counter i:2

Current counter i:3

Current counter j:2

Current counter i:4

Current counter i:5

Current counter j:3

Current counter i:6

Current counter i:7

Current counter j:4

Current counter i:8

Current counter i:9

Current counter j:5

Current counter i:10

。。。

四、创建X86镜像文件


图4.1 创建VxWorks镜像文件

 


图4.2 工程名称为vxworks_i386

 

图4.3 选择BSP和编译器

 

图4.4 该选择默认


图4.5 选择PROFILE_DEVELOPMENT

         如图4.5所示,我们选择“PROFILE_DEVELOPMENT”主要后面用到剪裁包含的组件,具体怎么操作,后面将会讲到。


图4.6 完成向导


图4.7 镜像文件树型结构

我们打开usrAppInit.c文件,添加一句简单的启动信息,最后编译镜像工程

/******************************************************************************

*

* usrAppInit - initialize theusers application

*/

 

voidusrAppInit (void)

    {

#ifdefUSER_APPL_INIT

    USER_APPL_INIT;     /* for backwards compatibility */

#endif

 

    /* addapplication specific code here */

    printf("Hello World!\n");

    }       

五、创建新连接


图5.1 新建一个仿真连接


图5.2 选择上述生成的镜像文件

 

图5.3 定制内存大小,此项默认即可


图5.4 优先级为belowNormal

 

图5.5 设置目标服务选择


图5.6 设置路径对象映射关系

 

图5.7 完成向导


图5.8 剪裁包含POSIX线程调度组件

 

图5.9有效的POSIX线程组件


图5.10 启动连接vxsim2

六、创建libice130动态连接库

        如何创建动态连接库及使用调用,参考之前《VxWorks6.6开发共享库指南要点》文档,然后工程注意事项如下:

        编译开关需要增加“-DVXWORKS -D__i386 -DICE_API_EXPORTS-Xrtti”


图6.1 编译选项

七、修改libice130源码

         这部分工作相对来说比较大,也是决定移植成功的关键阶段。总共按照8个方面修改,主要是适应VxWorks开发环境而配置的内容。

1、修改include/IceE/Cond.h文件

    #ifdef VXWORKS

       Time tm = Time::now() + timeout;

       timeval tv = tm.gettimeval();

#else

       timeval tv = Time::now() + timeout;

#endif

2、修改include/IceE/Mutex.h文件

1)增加包含文件

#ifdef VXWORKS

#include<semLib.h>

#endif

2)修改Mutex::init(…)函数

inline void

Mutex::init(MutexProtocol protocol)

{

#if defined(__linux) &&!defined(__USE_UNIX98)

#  ifdef NDEBUG

   int rc = pthread_mutex_init(&_mutex, 0);

#  else

   pthread_mutexattr_t attr = { PTHREAD_MUTEX_ERRORCHECK_NP };

   int rc = pthread_mutex_init(&_mutex, &attr);

#  endif

   if(rc != 0)

   {

        throw ThreadSyscallException(__FILE__,__LINE__, rc);

   }

#elifdefined(VXWORKS)

    //memset(&_mutex, '\0',sizeof(_mutex));

    int rc = pthread_mutex_init(&_mutex,0);

    assert(rc == 0);

    if (rc != 0)

    {

        throw ThreadSyscallException(__FILE__,__LINE__, rc);

    }

#else // !defined(__linux) || defined(__USE_UNIX98)

   pthread_mutexattr_t attr;

   int rc = pthread_mutexattr_init(&attr);

   assert(rc == 0);

   if(rc != 0)

   {

        throw ThreadSyscallException(__FILE__,__LINE__, rc);

   }

 

   //

   // Enable mutex error checking in debug builds

   //

#ifndef NDEBUG

   rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);

   assert(rc == 0);

   if(rc != 0)

   {

        throw ThreadSyscallException(__FILE__,__LINE__, rc);

   }

#endif

 

   //

   // If system has support for priority inheritance we set the protocol

   // attribute of the mutex

   //

#ifdefined(_POSIX_THREAD_PRIO_INHERIT) && _POSIX_THREAD_PRIO_INHERIT >0

   if(PrioInherit == protocol)

   {

        rc =pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);

        if(rc != 0)

        {

            throwThreadSyscallException(__FILE__, __LINE__, rc);

        }

   }

#endif

 

   rc = pthread_mutex_init(&_mutex, &attr);

   assert(rc == 0);

   if(rc != 0)

   {

        throw ThreadSyscallException(__FILE__,__LINE__, rc);

   }

 

   rc = pthread_mutexattr_destroy(&attr);

   assert(rc == 0);

   if(rc != 0)

   {

        throw ThreadSyscallException(__FILE__,__LINE__, rc);

   }

#endif

}

3)、修改include/IceE/NetWork.h文件

#ifdef _WIN32

#  include <winsock2.h>

typedef int ssize_t;

#else

#  include <unistd.h>

#  include <fcntl.h>

#  include <sys/socket.h>

#  if defined(__hpux)

#      include <sys/time.h>

#  else

#ifndef VXWORKS

#      include <sys/poll.h>

#endif

#      include <sys/time.h>

#  endif

3、修改include/IceE/Time.h文件

1)增加下面包含文件

#ifndef_WIN32_WCE

#   if defined(_WIN32)

#       include <sys/timeb.h>

#       include <time.h>

#   else

#       include <sys/time.h>

#   endif

#endif

2)修改Time类

#ifndef _WIN32

#ifdef VXWORKS

    timeval gettimeval() const;

#else

    operator timeval()const;

#endif

#endif

4、修改src/IceE/Instance.cpp文件

#ifdef _WIN32

#  include <winsock2.h>

#  ifndef _WIN32_WCE

#      include <process.h>

#  endif

#else

#  include <signal.h>

#ifndef VXWORKS

#  include <pwd.h>

#endif

#  include <sys/types.h>

#endif

 

using namespace std;

using namespace Ice;

using namespace IceInternal;

if(!newUser.empty())

                {

#ifndef VXWORKS                               

                    struct passwd* pw =getpwnam(newUser.c_str());

                    if(!pw)

                    {

                        SyscallExceptionex(__FILE__, __LINE__);

                        ex.error =getSystemErrno();

                        throw ex;

                    }

 

                    if(setgid(pw->pw_gid) ==-1)

                    {

                        SyscallExceptionex(__FILE__, __LINE__);

                        ex.error =getSystemErrno();

                        throw ex;

                    }

 

                    if(setuid(pw->pw_uid) ==-1)

                    {

                        SyscallExceptionex(__FILE__, __LINE__);

                        ex.error =getSystemErrno();

                        throw ex;

                    }

#endif

 

5、修改src/IceE/NetWork.cpp文件

1)修改包含文件

# include <sys/ioctl.h>

# include <net/if.h>

#ifdef VXWORKS

#   include <ioLib.h>

#   include <sockLib.h>

#define socklen_tint

#endif

# ifdef __sun

#   include <sys/sockio.h>

# endif

#endif

2)修改setBlock(…)函数

void

IceInternal::setBlock(SOCKET fd,bool block)

{

   if(block)

   {

#ifdef _WIN32

        unsigned long arg = 0;

        if(ioctlsocket(fd, FIONBIO, &arg)== SOCKET_ERROR)

        {

            closeSocketNoThrow(fd);

            SocketException ex(__FILE__, __LINE__);

            ex.error = WSAGetLastError();

            throw ex;

        }

#elif VXWORKS

        unsigned long lNonBlock = 0;

        if (ioctl(fd, FIONBIO, &lNonBlock)== SOCKET_ERROR)

        {

                 closeSocketNoThrow(fd);

                 SocketExceptionex(__FILE__, __LINE__);

                 ex.error= errno;

                 throwex;

        }

#else

        int flags = fcntl(fd, F_GETFL);

        flags &= ~O_NONBLOCK;

        if(fcntl(fd, F_SETFL, flags) ==SOCKET_ERROR)

        {

            closeSocketNoThrow(fd);

            SocketException ex(__FILE__,__LINE__);

            ex.error = errno;

            throw ex;

        }

#endif

   }

   else

   {

#ifdef _WIN32

        unsigned long arg = 1;

        if(ioctlsocket(fd, FIONBIO, &arg)== SOCKET_ERROR)

       {

            closeSocketNoThrow(fd);

            SocketException ex(__FILE__,__LINE__);

            ex.error = WSAGetLastError();

            throw ex;

        }

#elif VXWORKS

        unsigned long lNonBlock = 1;

        if (ioctl(fd, FIONBIO, &lNonBlock)== SOCKET_ERROR)

        {

                 closeSocketNoThrow(fd);

                 SocketExceptionex(__FILE__, __LINE__);

                 ex.error= errno;

                 throwex;

        }

#else

        int flags = fcntl(fd, F_GETFL);

        flags |= O_NONBLOCK;

        if(fcntl(fd, F_SETFL, flags) ==SOCKET_ERROR)

        {

            closeSocketNoThrow(fd);

            SocketException ex(__FILE__,__LINE__);

            ex.error = errno;

            throw ex;

        }

#endif

   }

}

3)修改createPipe (…)函数

void

IceInternal::createPipe(SOCKETfds[2])

{

#ifdef _WIN32

 

   SOCKET fd = createSocket();

   setBlock(fd, true);

 

   struct sockaddr_in addr;

   memset(&addr, 0, sizeof(addr));

 

   struct sockaddr_in* addrin = reinterpret_cast<structsockaddr_in*>(&addr);

   addrin->sin_family = AF_INET;

   addrin->sin_port = htons(0);

   addrin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);

 

   doBind(fd, addr);

   doListen(fd, 1);

 

   try

   {

        fds[0] = createSocket();

   }

   catch(...)

   {

        ::closesocket(fd);

        throw;

   }

 

   try

   {

        setBlock(fds[0], true);

#ifndef NDEBUG

        bool connected = doConnect(fds[0],addr);

        assert(connected);

#else

        doConnect(fds[0], addr);

#endif

   }

   catch(...)

   {

        // fds[0] is closed by doConnect

        ::closesocket(fd);

        throw;

   }

 

   try

   {

        fds[1] = doAccept(fd);

   }

   catch(...)

   {

        ::closesocket(fds[0]);

        ::closesocket(fd);

        throw;

   }

 

   ::closesocket(fd);

 

   try

    {

        setBlock(fds[1], true);

   }

   catch(...)

   {

        ::closesocket(fds[0]);

        // fds[1] is closed by setBlock

        throw;

   }

#elifdefined(VXWORKS)

 

    SOCKET fd = createSocket();

    setBlock(fd, true);

 

    struct sockaddr_in addr;

    memset(&addr, 0, sizeof(addr));

 

    struct sockaddr_in* addrin =reinterpret_cast<struct sockaddr_in*>(&addr);

    addrin->sin_family = AF_INET;

    addrin->sin_port = htons(0);

    addrin->sin_addr.s_addr =htonl(INADDR_LOOPBACK);

 

    doBind(fd, addr);

    doListen(fd, 1);

 

    try

    {

        fds[0] = createSocket();

    }

    catch(...)

    {

        ::close(fd);

        throw;

    }

 

    try

    {

        setBlock(fds[0], true);

#ifndef NDEBUG

        bool connected = doConnect(fds[0],addr);

        assert(connected);

#else

        doConnect(fds[0], addr);

#endif

    }

    catch(...)

    {

        // fds[0] is closed by doConnect

        ::close(fd);

        throw;

    }

 

    try

    {

        fds[1] = doAccept(fd);

    }

    catch(...)

    {

        ::close(fds[0]);

        ::close(fd);

        throw;

    }

 

    ::close(fd);

 

    try

    {

        setBlock(fds[1], true);

    }

    catch(...)

    {

        ::close(fds[0]);

        // fds[1] is closed by setBlock

        throw;

    }

#else

 

   if(::pipe(fds) != 0)

   {

        SyscallException ex(__FILE__,__LINE__);

        ex.error = getSystemErrno();

        throw ex;

   }

 

   try

   {

        setBlock(fds[0], true);

   }

   catch(...)

   {

        // fds[0] is closed by setBlock

        closeSocketNoThrow(fds[1]);

        throw;

   }

 

   try

   {

        setBlock(fds[1], true);

   }

   catch(...)

   {

        closeSocketNoThrow(fds[0]);

        // fds[1] is closed by setBlock

        throw;

   }

 

#endif

}

6、修改src/IceE/Selector.h文件

1)修改包含文件与宏定义

#if defined(__linux) &&!defined(ICE_NO_EPOLL)

#  define ICE_USE_EPOLL 1

#elif defined(__APPLE__) &&!defined(ICE_NO_KQUEUE)

#  define ICE_USE_KQUEUE 1

#elif defined(_WIN32)

#  define ICE_USE_SELECT 1

#elif  defined(VXWORKS)

#   define ICE_USE_SELECT 1

#endif

 

#if defined(ICE_USE_EPOLL)

#ifndef VXWORKS

#  include <sys/epoll.h>

#endif

#elif defined(ICE_USE_KQUEUE)

#  include <sys/event.h>

#else

#  if !defined(ICE_USE_SELECT)

#ifndef VXWORKS

#     include <sys/poll.h>

#endif

#  endif

#  include <list>

#endif

 

#ifdef VXWORKS

#   include <strings.h>

#endif

#include<IceE/NormalUtil.h>

2)修改函数select(…)

int select()

   {

       while(true)

       {

            int ret;

            _nSelectedReturned = 0;

            _nSelected = 0;

#if defined(ICE_USE_EPOLL)

            ret = epoll_wait(_queueFd,&_events[0], _events.size(), _timeout > 0 ? _timeout * 1000 : -1);

#elif defined(ICE_USE_KQUEUE)

            assert(!_events.empty());

            if(_timeout > 0)

            {

                struct timespec ts;

                ts.tv_sec = _timeout;

                ts.tv_nsec = 0;

                ret = kevent(_queueFd, 0, 0,&_events[0], _events.size(), &ts);

            }

            else

            {

                ret = kevent(_queueFd, 0, 0,&_events[0], _events.size(), 0);

            }

#elif defined(ICE_USE_SELECT)

            fd_set* rFdSet =fdSetCopy(_selectedReadFdSet, _readFdSet);

            fd_set* wFdSet =fdSetCopy(_selectedWriteFdSet, _writeFdSet);

            fd_set* eFdSet =fdSetCopy(_selectedErrorFdSet, _errorFdSet);

            int nFd = 0;

#ifndef WIN32

            nFd = FD_SETSIZE;     

#endif           

            if(_timeout > 0)

            {

                struct timeval tv;

                tv.tv_sec = _timeout;

                tv.tv_usec = 0;

                ret = ::select(nFd, rFdSet, wFdSet, eFdSet, &tv); // The firstparameter is ignored on Windows

            }

            else

            {

                ret = ::select(nFd, rFdSet, wFdSet, eFdSet, 0); // The firstparameter is ignored on Windows

            }

#else

            ret = poll(&_pollFdSet[0], _pollFdSet.size(),_timeout > 0 ? _timeout * 1000 : -1);

#endif

            if(ret == SOCKET_ERROR)

            {

                if(interrupted())

                {

                    continue;

                }

 

                assert(false);

                Ice::SocketException ex(__FILE__, __LINE__);

                ex.error = getSocketErrno();

                throw ex;

            }

 

            assert(ret >= 0);

            _nSelected =static_cast<unsigned int>(ret);

            if(_nSelected == 0)

           {

                assert(_timeout > 0);

                _timeout = 0;

            }

            return _nSelected;

       }

}

3)修改函数getNextSelected (…)函数

 T* getNextSelected()

   {

       assert(_nSelected > 0);

 

#if defined(ICE_USE_EPOLL) ||defined(ICE_USE_KQUEUE)

       if(_nSelectedReturned == _nSelected)

       {

            if(_count != _events.size())

            {

               _events.resize(_count);

            }

            return 0;

       }

 

       //

       // Round robin for the filedescriptors.

       //

       T* larger = 0;

       T* smallest = 0;

       for(unsigned int i = 0; i < _nSelected; ++i)

        {

#if defined(ICE_USE_EPOLL)

            T* handler =reinterpret_cast<T*>(_events[i].data.ptr);

#else

            T* handler =reinterpret_cast<T*>(_events[i].udata);

#endif

            if(!handler) // _fdIntrRead

            {

                assert(_nSelectedReturned >0 && _interruptCount == 0);

                continue;

            }

 

            if(handler->_fd > _lastFd&& (larger == 0 || handler->_fd < larger->_fd))

            {

                larger = handler;

            }

 

            if(smallest == 0 || handler->_fd< smallest->_fd)

            {

                smallest = handler;

            }

       }

 

       ++_nSelectedReturned;

       if(larger)

       {

            _lastFd = larger->_fd;

            return larger;

       }

       else

       {

            assert(smallest);

            _lastFd = smallest->_fd;

            return smallest;

       }

#else

       if(_nSelectedReturned == _nSelected)

       {

            return 0;

       }

 

       //

       // Round robin for the filedescriptors.

       //

       SOCKET largerFd = INVALID_SOCKET;

       SOCKET smallestFd = INVALID_SOCKET;

#if defined(ICE_USE_SELECT)

#ifdef VXWORKS

        int nFdsetMaxCount =howmany(FD_SETSIZE, NFDBITS);

        int nReadFdSetCount = 0;

        int nWriteFdSetCount = 0;

        int nErrorFdSetCount = 0;

        for (int j = 0; j < nFdsetMaxCount;++j)

        {

                 intnCount1 = IceUtil::getFdsetBits(_selectedReadFdSet.fds_bits[j]);

                 nReadFdSetCount+= nCount1;

                

                 int nCount2 =IceUtil::getFdsetBits(_selectedWriteFdSet.fds_bits[j]);

                 nWriteFdSetCount+= nCount2;

                                 

                 intnCount3 = IceUtil::getFdsetBits(_selectedErrorFdSet.fds_bits[j]);

                 nErrorFdSetCount+= nCount3;

        }

       

        if (nReadFdSetCount == 0 &&nWriteFdSetCount == 0 && nErrorFdSetCount == 0)

        {

            Ice::Errorout(_instance->initializationData().logger);

            out << "select() inselector returned " << _nSelected << " but no filedescriptoris ready";

            return 0;

        }

        int nfdSetCount = 0;              

        const fd_set* fdSet;

        if (_nSelectedReturned <nReadFdSetCount)

        {

            fdSet = &_selectedReadFdSet;

            nfdSetCount = nReadFdSetCount;

        }

        else if (_nSelectedReturned <nWriteFdSetCount + nReadFdSetCount)

        {

            fdSet = &_selectedWriteFdSet;

            nfdSetCount = nWriteFdSetCount;

        }

        else

        {

            fdSet = &_selectedErrorFdSet;

            nfdSetCount = nErrorFdSetCount;

        }

      

        for (u_short i = 0; i < FD_SETSIZE;++i)

        {

            if (!FD_ISSET(i, fdSet))

            {

                continue;

            }

            SOCKET fd = i;

#else

       if(_selectedReadFdSet.fd_count == 0 &&_selectedWriteFdSet.fd_count == 0 && _selectedErrorFdSet.fd_count == 0)

       {

            Ice::Errorout(_instance->initializationData().logger);

            out << "select() inselector returned " << _nSelected << " but nofiledescriptor is ready";

            return 0;

       }

 

       const fd_set* fdSet;

       if(_nSelectedReturned < _selectedReadFdSet.fd_count)

       {

            fdSet = &_selectedReadFdSet;

       }

       else if(_nSelectedReturned < _selectedWriteFdSet.fd_count +_selectedReadFdSet.fd_count)

       {

            fdSet = &_selectedWriteFdSet;

       }

       else

       {

            fdSet = &_selectedErrorFdSet;

       }

       for(u_short i = 0; i < fdSet->fd_count; ++i)

       {

           SOCKET fd = fdSet->fd_array[i];

#endif

#else

       for(std::vector<struct pollfd>::const_iterator p =_pollFdSet.begin(); p != _pollFdSet.end(); ++p)

       {

            if(p->revents == 0)

            {

                continue;

            }

            SOCKET fd = p->fd;

#endif

            if(fd == _fdIntrRead)

            {

                assert(_nSelectedReturned >0 && _interruptCount == 0);

                continue;

            }

 

            assert(fd != INVALID_SOCKET);

            if(fd > _lastFd &&(largerFd == INVALID_SOCKET || largerFd > fd))

            {

                largerFd = fd;

            }

 

            if(smallestFd == INVALID_SOCKET ||fd < smallestFd)

            {

                smallestFd = fd;

           }

       }

 

       if(largerFd != INVALID_SOCKET)

       {

            _lastFd = largerFd;

       }

       else

       {

            assert(smallestFd !=INVALID_SOCKET);

            _lastFd = smallestFd;

       }

 

       typename std::map<SOCKET, T*>::const_iterator q =_handlerMap.find(_lastFd);

       if(q == _handlerMap.end())

       {

            Ice::Errorout(_instance->initializationData().logger);

            out << "filedescriptor" << static_cast<int>(_lastFd) << " not registeredwith selector";

            return 0;

       }

       ++_nSelectedReturned;

       return q->second;

#endif

}

7、修改src/IceE/Thread.cpp文件

1)修改包含文件与宏定义

#ifdef VXWORKS

#include<taskLib.h>

extern "C"int sysClkRateGet(void);

#endif

2)修改sleep(…)函数

void

IceUtil::ThreadControl::sleep(constTime& timeout)

{

#ifdef VXWORKS

         struct timeval tv =timeout.gettimeval();

#else

   struct timeval tv = timeout;

#endif

   struct timespec ts;

   ts.tv_sec = tv.tv_sec;

   ts.tv_nsec = tv.tv_usec * 1000L;

   nanosleep(&ts, 0);

}

3)修改Time::now (…)函数

 

Time

IceUtil::Time::now(Clock clock)

{

#if defined(_WIN32_WCE)

   //

   // Note that GetTickCount returns the number of ms since the

   // device was started. Time cannot be used to represent an

   // absolute time on CE since GetLocalTime doesn't have millisecond

   // resolution.

   //

   return Time(static_cast<Int64>(GetTickCount()) * 1000);

#else

   if(clock == Realtime)

   {

# if defined(_WIN32)

       struct _timeb tb;

       _ftime(&tb);

       return Time(static_cast<Int64>(tb.time) * ICE_INT64(1000000) +tb.millitm * 1000);

# else

#ifdef VXWORKS

        struct timespec ts;

        if(clock_gettime(CLOCK_MONOTONIC,&ts) < 0)

        {

            assert(0);

            throwIce::SyscallException(__FILE__, __LINE__, errno);

        }

        return Time(ts.tv_sec *ICE_INT64(1000000) + ts.tv_nsec / ICE_INT64(1000));

#else

       struct timeval tv;

       if(gettimeofday(&tv, 0) < 0)

       {

            assert(0);

            throwIce::SyscallException(__FILE__, __LINE__, errno);

       }

       return Time(tv.tv_sec * ICE_INT64(1000000) + tv.tv_usec);

#endif

# endif

   }

   else

   {

#if defined(_WIN32)

       if(frequency > 0.0)

       {

            Int64 count;

            if(!QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&count)))

            {

                assert(0);

                throwIce::SyscallException(__FILE__, __LINE__, GetLastError());

            }

            returnTime(static_cast<Int64>(count / frequency * 1000000.0));

       }

       else

       {

            struct _timeb tb;

            _ftime(&tb);

            returnTime(static_cast<Int64>(tb.time) * ICE_INT64(1000000) + tb.millitm *1000);

       }

#elif defined(__hpux) ||defined(__APPLE__)

       //

       // Platforms do not support CLOCK_MONOTONIC

       //

       struct timeval tv;

       if(gettimeofday(&tv, 0) < 0)

       {

            assert(0);

            throwIce::SyscallException(__FILE__, __LINE__, errno);

       }

       return Time(tv.tv_sec * ICE_INT64(1000000) + tv.tv_usec);

#else

       struct timespec ts;

       if(clock_gettime(CLOCK_MONOTONIC, &ts) < 0)

       {

            assert(0);

            throwIce::SyscallException(__FILE__, __LINE__, errno);

       }

       return Time(ts.tv_sec * ICE_INT64(1000000) + ts.tv_nsec /ICE_INT64(1000));

#endif

 

   }

#endif

}

4)修改Time:: timeval (…)函数

#ifndef _WIN32

#ifdef VXWORKS

timevalIceUtil::Time::gettimeval() const

{

         timeval tv;

         tv.tv_sec =static_cast<long>(_usec / 1000000);

         tv.tv_usec =static_cast<long>(_usec % 1000000);

         return tv;

}

#else

IceUtil::Time::operator timeval()const

{

   timeval tv;

   tv.tv_sec = static_cast<long>(_usec / 1000000);

   tv.tv_usec = static_cast<long>(_usec % 1000000);

   return tv;

}

#endif

#endif

 

8、创建两个文件

1)src/IceE/ NormalUtil.h文件

//**********************************************************************

//

//Copyright (c) 2015

//

//2015.02.11

// 平台软件部, 上海

// AllRights Reserved

//

//**********************************************************************

#ifndef_NORMALUTIL_H_

#define_NORMALUTIL_H_

 

namespaceIceUtil

{

 

ICE_APIint getFdsetBits(unsigned int nFd);

 

};

 

#endif// _NORMALUTIL_H_

2)src/IceE/ NormalUtil.cpp文件

//**********************************************************************

//

//Copyright (c) 2015

//

//2015.02.11

// 平台软件部, 上海

// AllRights Reserved

//

//**********************************************************************

#include<IceE/Config.h>

#include<IceE/NormalUtil.h>

 

staticconst unsigned char bits_table[256] =

{

         0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,

         1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3,4, 4, 5,

         1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3,4, 4, 5,

         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4,5, 5, 6,

         1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4,4, 5,

         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4,5, 5, 6,

         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4,5, 5, 6,

         3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,6, 6, 7,

         1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3,4, 4, 5,

         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4,5, 5, 6,

         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4,5, 5, 6,

         3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,6, 6, 7,

         2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4,5, 5, 6,

         3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,6, 6, 7,

         3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5,6, 6, 7,

         4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6,7, 7, 8

};

 

int

IceUtil::getFdsetBits(unsignedint nFd)

{

         int nCount = 0;

         nCount = bits_table[nFd & 0xff] + \

                        bits_table[(nFd >> 8) & 0xff];

         return nCount;

}

八、测试范例

这是Ice1.3.0本身自带的例子,稍微加以修改。两个工程都是RTP为基础,具体如何引用so,以及相关的工程配置,请参考《VxWorks6.6开发共享库指南要点》文档。

编译开关需要增加“-DVXWORKS -D__i386-DICE_API_EXPORTS”

1、创建服务端程序

//**********************************************************************

//

//Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved.

//

// Thiscopy of Ice-E is licensed to you under the terms described in the

//ICEE_LICENSE file included in this distribution.

//

//**********************************************************************

 

#include <IceE/IceE.h>

#include "HelloI.h"

 

using namespace std;

 

int

run(int argc, char*argv[], const Ice::CommunicatorPtr&communicator)

{

    if(argc> 1)

    {

        fprintf(stderr, "%s: too many arguments\n", argv[0]);

        returnEXIT_FAILURE;

    }

 

    Ice::ObjectAdapterPtr adapter =communicator->createObjectAdapter("Hello");

    Demo::HelloPtr object = new HelloI;

    adapter->add(object,communicator->stringToIdentity("hello"));

    adapter->activate();

    communicator->waitForShutdown();

    returnEXIT_SUCCESS;

}

 

int

main(int argc, char*argv[])

{

    int status;

    Ice::CommunicatorPtr communicator;

 

    try

    {

        Ice::InitializationData initData;

        initData.properties =Ice::createProperties();

        initData.properties->load("/d/casco800A/fep/config/config.server");

        communicator = Ice::initialize(argc,argv, initData);

        status = run(argc, argv, communicator);

    }

    catch(const Ice::Exception& ex)

    {

        fprintf(stderr, "%s\n", ex.toString().c_str());

        status = EXIT_FAILURE;

    }

 

    if(communicator)

    {

        try

        {

            communicator->destroy();

        }

        catch(const Ice::Exception& ex)

        {

            fprintf(stderr, "%s\n", ex.toString().c_str());

            status = EXIT_FAILURE;

        }

    }

 

    returnstatus;

}

2、创建客户端程序

//**********************************************************************

//

//Copyright (c) 2003-2008 ZeroC, Inc. All rights reserved.

//

// Thiscopy of Ice-E is licensed to you under the terms described in the

//ICEE_LICENSE file included in this distribution.

//

//**********************************************************************

 

#include <IceE/IceE.h>

#include "Hello.h"

 

using namespace std;

using namespace Demo;

 

void

menu()

{

    printf("usage:\n");

    printf("t:send greeting as twoway\n");

    printf("o:send greeting as oneway\n");

#ifdef ICEE_HAS_BATCH

    printf("O:send greeting as batch oneway\n");

    printf("f:flush all batch requests\n");

#endif

    printf("T:set a timeout\n");

    printf("P:set a server delay\n");

    printf("s:shutdown server\n");

    printf("x:exit\n");

    printf("?:help\n");

}

 

int

run(int argc, char*argv[], const Ice::CommunicatorPtr&communicator)

{

    if(argc> 1)

    {

        fprintf(stderr, "%s: too many arguments\n", argv[0]);

        returnEXIT_FAILURE;

    }

 

    Ice::PropertiesPtr properties =communicator->getProperties();

    const char* proxyProperty = "Hello.Proxy";

    string proxy = properties->getProperty(proxyProperty);

    if(proxy.empty())

    {

        fprintf(stderr, "%s: property `%s' not set\n", argv[0],proxyProperty);

        returnEXIT_FAILURE;

    }

 

    Ice::ObjectPrx base =communicator->stringToProxy(proxy);

    HelloPrx twoway = HelloPrx::checkedCast(base->ice_twoway()->ice_timeout(-1));

    if(!twoway)

    {

        fprintf(stderr, "%s: invalid proxy\n", argv[0]);

        returnEXIT_FAILURE;

    }

    HelloPrx oneway = twoway->ice_oneway();

#ifdef ICEE_HAS_BATCH

    HelloPrx batchOneway = twoway->ice_batchOneway();

#endif

 

    int timeout= -1;

    int delay =0;

 

    menu();

 

    char c =EOF;

    do

    {

        try

        {

            printf("==>"); fflush(stdout);

            do

            {

                c = getchar();

            }

            while(c!= EOF && c =='\n');

            if(c== 't')

            {

                twoway->sayHello(delay);

            }

            elseif(c =='o')

            {

                oneway->sayHello(delay);

            }

#ifdef ICEE_HAS_BATCH

            elseif(c =='O')

            {

               batchOneway->sayHello(delay);

            }

            elseif(c =='f')

            {

               batchOneway->ice_flushBatchRequests();

            }

#endif

            elseif(c =='T')

            {

                if(timeout== -1)

                {

                    timeout = 2000;

                }

                else

                {

                    timeout = -1;

                }

               

                twoway = twoway->ice_timeout(timeout);

                oneway =oneway->ice_timeout(timeout);

#ifdef ICEE_HAS_BATCH

                batchOneway =batchOneway->ice_timeout(timeout);

#endif               

                if(timeout== -1)

                {

                    printf("timeoutis now switched off\n");

                }

                else

                {

                    printf("timeout is now set to 2000ms\n");

                }

            }

            elseif(c =='P')

            {

                if(delay== 0)

                {

                    delay = 2500;

                }

                else

                {

                    delay = 0;

                }

               

                if(delay== 0)

                {

                    printf("serverdelay is now deactivated\n");

                }

                else

                {

                    printf("server delay is now set to 2500ms\n");

                }

            }

            elseif(c =='s')

            {

               twoway->shutdown();

            }

            elseif(c =='x')

            {

                //Nothing to do

            }

            elseif(c =='?')

            {

                menu();

            }

            else

            {

                printf("unknowncommand `%c'\n", c);

                menu();

            }

        }

        catch(const Ice::Exception& ex)

        {

            fprintf(stderr, "%s\n", ex.toString().c_str());fflush(stderr);

        }

    }

    while(c !=EOF && c != 'x');

 

    returnEXIT_SUCCESS;

}

 

int

main(int argc, char*argv[])

{

    int status;

    Ice::CommunicatorPtr communicator;

 

    try

    {

        Ice::InitializationData initData;

        initData.properties =Ice::createProperties();

        initData.properties->load("/d/casco800A/fep/config/config.client");

        communicator = Ice::initialize(argc,argv, initData);

        status = run(argc, argv, communicator);

    }

    catch(const Ice::Exception& ex)

    {

        fprintf(stderr, "%s\n", ex.toString().c_str());

        status = EXIT_FAILURE;

    }

 

    if(communicator)

    {

        try

        {

            communicator->destroy();

        }

        catch(const Ice::Exception& ex)

        {

            fprintf(stderr, "%s\n", ex.toString().c_str());

            status = EXIT_FAILURE;

        }

    }

 

    returnstatus;

}

3、运行测试

3.1、执行客户与服务程序


图8.1 并行运行的程序以不同颜色标识

3.2、查看端口使用状况

1)启动服务端时的状态

-> netstat "-ap tcp"

INET sockets

Prot  Fd   Recv-Q Send-Q Local Address                 Foreign Address               State

TCP   46   0     0      localhost.49176               localhost.49175               ESTABLISHED

TCP   47   0     0      localhost.49175               localhost.49176               ESTABLISHED

TCP   49   0     0      localhost.49178               localhost.49177               ESTABLISHED

TCP   50   0     0      localhost.49177               localhost.49178               ESTABLISHED

TCP   51   0     0      localhost.10000               0.0.0.0.*                     LISTEN    

TCP   53   0     0      localhost.49180               localhost.49179               ESTABLISHED

TCP   54   0     0      localhost.49179               localhost.49180               ESTABLISHED

 

INET6 sockets

Prot  Fd   Recv-Q Send-Q Local Address                 Foreign Address               State

 

 

value = 0 = 0x0

->

2)启动客户端时的状态

-> netstat "-ap tcp"

INET sockets

Prot  Fd   Recv-Q Send-Q Local Address                 Foreign Address               State

TCP   46   0     0      localhost.49176               localhost.49175               ESTABLISHED

TCP   47   0     0      localhost.49175               localhost.49176               ESTABLISHED

TCP   49   0     0      localhost.49178               localhost.49177               ESTABLISHED

TCP   50   0     0      localhost.49177               localhost.49178               ESTABLISHED

TCP   51   0     0      localhost.10000               0.0.0.0.*                     LISTEN    

TCP   53   0     0      localhost.49180               localhost.49179               ESTABLISHED

TCP   54   0     0      localhost.49179               localhost.49180               ESTABLISHED

TCP   56   0     0      localhost.49182               localhost.49181               ESTABLISHED

TCP   57   0     0      localhost.49181               localhost.49182               ESTABLISHED

TCP   59   0     0      localhost.49184               localhost.49183               ESTABLISHED

TCP   60   0     0      localhost.49183               localhost.49184               ESTABLISHED

TCP   61   0     0      localhost.49185               localhost.10000               ESTABLISHED

TCP   62   0     0      localhost.10000               localhost.49185               ESTABLISHED

 

INET6 sockets

Prot  Fd   Recv-Q Send-Q Local Address                 Foreign Address               State

 

 

value = 0 = 0x0

->

3.3、控制台输出结果

1)testclient.vxe控制台

usage:

t: send greeting as twoway

o: send greeting as oneway

O: send greeting as batch oneway

f: flush all batch requests

T: set a timeout

P: set a server delay

s: shutdown server

x: exit

?: help

==> t

输入命令t,回车

2)testIce130控制台

      Hello World!

 

现在你看到上面的输出结果,这是否令人激动呢?!

九、总结

         本文详细描述了基于POSIX移植可能出现的问题,修改的代码并不是很大,我相信按照上述的步骤,移植iceE1.3.0到VxWorks操作系统下并不是难事了,你可以省下zeroC公司商业方面的技术支持费用了。

         你可能发现本文并没使用ice的makefile自动编译,为了简便移植工作,防止在vxWorks开发环境中安装第三方的库过于复杂。因此,我们只要从Windows下拷贝已经生成的源码,在此基础上再进行修改移植即可。

         我们已经成功地移植了 IceE1.3.0,如何在VxWorks操作系统中正确部署,那就看你的架构了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值