管道可以看作受驱动器pipeDrv管理的虚拟I/O设备,使用基本的I/O系统接口可以读、写和操作管道,这些函数包括read、write、open、close、ioctl和select等。与pipe密切相关的其它API还有:
(1)pipeDrv( ):初始化pipeDrv,函数原型:
STATUS pipeDrv (void);
(2)pipeDevCreate( ):创建pipe,函数原型:
STATUS pipeDevCreate
    (
    char name,              / 创建的pipe名 /
    int    nMessages,         /
pipe中的最大消息数 /
    int    nBytes             /
每个消息的大小 /
    );
(3)pipeDevDelete:删除pipe,函数原型:
STATUS pipeDevDelete
    (
    char
name,              / 要删除的pipe名 /
    BOOL   force              / 如果为真,则强制删除pipe /
    );
下面我们看看pipe使用的demo:
例3:管道
/ includes /
#include "vxWorks.h"
#include "taskLib.h"
#include "stdio.h"
#include "ioLib.h"
#include "pipeDrv.h"
 
/globals /
typedef struct
{
  VOIDFUNCPTR routine;   / 函数指针 /
  int arg;
} MSG_REQUEST; / message structure /
 
#define TASK_PRI          254             / tServers task's priority /
#define TASK_STACK_SIZE  5000      / tServer task's stack size /
#define PIPE_NAME       "/pipe/server"  / name of the pipe device /
#define NUM_MSGS  10     / max number of messages in the pipe /
 
LOCAL int pipeFd; / File descriptor for the pipe device /
LOCAL void pipeServer(); / server task /
 
/ serverStart:初始化pipeServer任务以执行管道中夹带的函数 /
STATUS serverStart()
{
  if (pipeDevCreate(PIPE_NAME, NUM_MSGS, sizeof(MSG_REQUEST)) == ERROR)
  {
    perror("Error in creating pipe"); / print error if pipe is already
    
created, but do not return /
  }
 
  /
Open the pipe /
  if ((pipeFd = open(PIPE_NAME, UPDATE, 0)) == ERROR)
  {
    perror("Error in opening pipe device");
    return (ERROR);
  }
 
  /
Spawn the server task /
  if (taskSpawn("tServer", TASK_PRI, 0, TASK_STACK_SIZE, (FUNCPTR)pipeServer, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0) == ERROR)
  {
    perror("Error in spawning tServer task");
    close(pipeFd);
    return (ERROR);
  }
 
  return (OK);
}
 
/
serverSend :发送管道消息,将函数指针作为消息的一部分 /
STATUS serverSend(VOIDFUNCPTR routine, /
name of the routine to execute / int arg / argument of the routine /
)
{
  MSG_REQUEST msgRequest;
  int status;
 
  /
Initialize the message structure /
  msgRequest.routine = routine;
  msgRequest.arg = arg;
 
  /
Send the message and return the results /
  status = write(pipeFd, (char
) &msgRequest, sizeof(MSG_REQUEST));
 
  return ((status == sizeof(MSG_REQUEST)) ? OK : ERROR);
}
 
/ pipeServer:读取管道消息并执行管道消息中夹带的函数 /
LOCAL void pipeServer()
{
  MSG_REQUEST msgRequest;
 
  while (read(pipeFd, (char) &msgRequest, sizeof(MSG_REQUEST)) > 0)
    (
msgRequest.routine)(msgRequest.arg);
}
   上述程序中,pipeServer执行于非常低的优先级(254级),当我们在shell中输入“serverSend(VOIDFUNCPTR routine, int arg)” 时,pipeServer将读到管道中的消息,并执行“routine (arg)”。
       为对此进行验证,我们在程序中再添加一个函数:
void PRINT(int arg)
{
       printf("%d",arg);
}
当我们在tShell中输入“serverSend(PRINT,2);”,在VxSim中将输出2。
9.套接字
不论网络中的节点使用什么操作系统,套接字的通信都是完全对等的。套接字有两种:
(1)流套接字(SOCK_STREAM,采用TCP协议):流套接字提供了双向的、有序的、无重复并且无记录边界的数据流服务;
(2)数据报套接字(SOCK_DGRAM,采用UDP协议):数据报套接字也支持双向数据传输,但并不保证是可靠、有序和无重复的。
另外还有一种RAW套接字,但不常见。
VxWorks中与Socket相关的函数有:
(1)socket():创建套接字   ,原型为:
int socket
    (
    int domain,    /
address family (for example, AF_INET) /
    int type,      /
SOCK_STREAM, SOCK_DGRAM, or SOCK_RAW /
    int protocol   /
socket protocol (usually 0) /
    );
(2)bind():给套接字绑定名称 ,原型为:
STATUS bind
    (
    int               s,      /
socket descriptor /
    struct sockaddr
name,   / name to be bound /
    int            namelen / length of name /
    );
(3)listen():服务端监听TCP连接请求,原型为:
STATUS listen
    (
    int s,                    / socket descriptor /
    int backlog               / number of connections to queue /
    );
(4)accept():服务端接受TCP连接请求,原型为:
int accept
    (
    int            s,      / socket descriptor /
    struct sockaddr addr,   / peer address /
    int
           addrlen / peer address length /
    );
(5)connect():客户端请求连接套接字,原型为:
STATUS connect
    (
    int               s,      / socket descriptor /
    struct sockaddr name,   / addr of socket to connect /
    int            namelen /
length of name, in bytes /
    );
(6)shutdown():关闭套接字间连接,原型为:
STATUS shutdown
    (
    int s,                /
socket to shut down /
    int how              /
0:receives disallowed;1:sends disallowed;
2:sends and receives disallowed /
    );
(7)sendto()、send()、sendmsg():发送数据
int sendto
    (
    int               s,      /
socket to send data to /
    caddr_t           buf,    /
pointer to data buffer /
    int               bufLen, /
length of buffer /
    int               flags,  /
flags to underlying protocols /
    struct sockaddr
to,     / recipient's address /
    int               tolen   / length of to sockaddr /
    );
 
int send
    (
    int          s,           / socket to send to /
    const char buf,         / pointer to buffer to transmit /
    int          bufLen,      /
length of buffer /
    int          flags        /
flags to underlying protocols /
    );
 
int sendmsg
    (
    int             sd,       /
socket to send to /
    struct msghdr
mp,       / scatter-gather message header /
    int             flags     / flags to underlying protocols /
    );
(8)recvfrom ()、recv ()、recvmsg ():接收数据
int recvfrom
    (
    int               s,       / socket to receive from /
    char             buf,     / pointer to data buffer /
    int               bufLen,  /
length of buffer /
    int               flags,   /
flags to underlying protocols /
    struct sockaddr
from,    / where to copy sender's addr /
    int              pFromLen / value/result length of from /
    );
 
int recv
    (
    int    s,                 /
socket to receive data from /
    char
buf,               / buffer to write data to /
    int    bufLen,            / length of buffer /
    int    flags              / flags to underlying protocols /
    );
 
int recvmsg
    (
    int             sd,       / socket to receive from /
    struct msghdr mp,       / scatter-gather message header /
    int             flags     /
flags to underlying protocols /
    );
限于篇幅的关系,我们在此不在列举socket通信的例子。但在最后一次连载的综合实例中,将包括完整的socket通信过程源代码。
10.信号与异常处理
信号是VxWorks中用于异常处理的方式,信号的驱动和执行机制有点类似于硬件中断(可以认为是一种软件上的通告,即software notification)。信号的生存期为从“产生”到“传递”,一个“产生”而未“传递”的信号处于pending状态。信号适宜进行异常处理,任务间的通信不要使用信号。
下面是从Embry-Riddle Real-Time Laboratory试验课程中获得的一个signal的例子:
例4:信号与异常处理
/
includes /
#include "vxWorks.h"
#include "sigLib.h"
#include "taskLib.h"
#include "stdio.h"
 
/
function prototypes /
void catchSIGINT(int);
void sigCatcher(void);
 
/
globals /
#define NO_OPTIONS 0
#define ITER1 100
#define LONG_TIME 1000000
#define HIGHPRIORITY 100
#define LOWPRIORITY 101
int ownId;
 
void sigGenerator(void) /
task to generate the SIGINT signal /
{
  int i, j, taskId;
  STATUS taskAlive;
 
  if ((taskId = taskSpawn("signal", 100, 0x100, 20000, (FUNCPTR)sigCatcher, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    printf("taskSpawn sigCatcher failed\n");
 
  ownId = taskIdSelf(); /
get sigGenerator's task id /
 
  taskDelay(30); /
allow time to get sigCatcher to run /
 
  for (i = 0; i < ITER1; i++)
  {
    if ((taskAlive = taskIdVerify(taskId)) == OK)
    {
      printf("+++++++++++++++++++++++++++++++SIGINT sinal generated\n");
      kill(taskId, SIGINT); /
generate signal /
      /
lower sigGenerator priority to allow sigCatcher to run /
      taskPrioritySet(ownId, LOWPRIORITY);
    }
    else
     /
sigCatcher is dead */
      break;
  }
  printf("\nsigGenerator Exited\n");
}
 
void sigCatcher(void) / task to handle the SIGINT signal /
{
  struct sigaction newAction;
  int i, j;
 
  newAction.sa_handler = catchSIGINT; / set the new handler /
  sigemptyset(&newAction.sa_mask); / no other signals blocked /
  newAction.sa_flags = NO_OPTIONS; / no special options /
 
  if (sigaction(SIGINT, &newAction, NULL) ==  - 1)
    printf("Could not install signal handler\n");
 
  for (i = 0; i < ITER1; i++)
  {
    for (j = 0; j < LONG_TIME; j++)
      ;
    printf("Normal processing in sigCatcher\n");
  }
 
  printf("\n+++++++++++++++sigCatcher Exited+++++++++++++++\n");
}
 
void catchSIGINT(int signal) / signal handler code /
{
  printf("-------------------------------SIGINT signal caught\n");
  / increase sigGenerator priority to allow sigGenerator to run /
  taskPrioritySet(ownId, HIGHPRIORITY);
}
分析以上程序,kill()函数产生信号,其原型为:
int kill
    (
    int tid,                  / task to send signal to /
    int signo                 / signal to send to task /
    );
sigaction()函数将信号与信号处理函数进行绑定,一个信号处理函数类似于程序中的catchSIGINT函数,一般结构为:
void sigHandlerFunction(int signalNumber)
{
... / signal handler code /
}
sigaction()函数的原型为:
int sigaction
    (
    int               signo, / signal of handler of interest /
    const struct sigaction pAct,  / location of new handler /
    struct sigaction
   pOact  / location to store old handler /
    );
 signo为信号序号,而输入参数pAct中存放的是信号处理函数的信息,pOact是一个输出参数,可以获得老的信号处理函数信息。
运行上述程序,输出结果为:
Normal processing in sigCatcher 
…     //大量的Normal processing in sigCatcher
Normal processing in sigCatcher 
+++++++++++++++sigCatcher Exited+++++++++++++++
————————————————