一、前言
ICE1.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 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.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
typedef int ssize_t;
#else
# include "unistd.h"
# include "fcntl.h"
# include "sys/socket.h"
<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 "signal.h"
# include
#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
# include
#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(&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(&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
#endif
#ifdef VXWORKS
# include
#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(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(_events[i].data.ptr);
#else
T* handler =reinterpret_cast(_events[i].udata);
#endif
if(!handler) // _fdIntrRead
{
assert(_nSelectedReturned >0 && _interruptCount == 0);
continue;
}
if(handler->_fd > _lastFd&& (larger == 0 || handler->_fd _fd))
{
larger = handler;
}
if(smallest == 0 || handler->_fd_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 initializationData().logger);
out << "select() inselector returned " << _nSelected << " but no filedescriptoris ready";
return 0;
}
int nfdSetCount = 0;
const fd_set* fdSet;
if (_nSelectedReturned 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 fd_count; ++i)
{
SOCKET fd = fdSet->fd_array[i];
#endif
#else
for(std::vector::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 ::const_iterator q =_handlerMap.find(_lastFd);
if(q == _handlerMap.end())
{
Ice::Errorout(_instance->initializationData().logger);
out << "filedescriptor" <(_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(GetTickCount()) * 1000);
#else
if(clock == Realtime)
{
# if defined(_WIN32)
struct _timeb tb;
_ftime(&tb);
return Time(static_cast(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(&count)))
{
assert(0);
throwIce::SyscallException(__FILE__, __LINE__, GetLastError());
}
returnTime(static_cast(count / frequency * 1000000.0));
}
else
{
struct _timeb tb;
_ftime(&tb);
returnTime(static_cast(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(_usec / 1000000);
tv.tv_usec =static_cast(_usec % 1000000);
return tv;
}
#else
IceUtil::Time::operator timeval()const
{
timeval tv;
tv.tv_sec = static_cast(_usec / 1000000);
tv.tv_usec = static_cast(_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;
}
}
return(status);
}
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);
return(EXIT_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]);
return(EXIT_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');
return(EXIT_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;
}
}
return(status);
}
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操作系统中正确部署,那就看你的架构了。