管道可以看作受驱动器
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("\n***************sigGenerator 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+++++++++++++++
我们将从下一次连载――《
VxWorks
中断处理》中发现中断与信号的相似性。