我尝试设置两个守护进程,一个客户端和一个服务器,服务器分析一些系统统计信息,并以非阻塞方式等待接收 SIGIO,然后它将读取发送给它的数据,将一些内容发送回客户端并继续执行正在执行的操作。
但是,客户端在其套接字上发出了阻塞发送和接收函数。我已经编写了相当多的代码,并广泛阅读,但似乎人们在尝试实现这种行为时使用了很多不同的范例,我真的很感激一些帮助,这是我目前的代码:
服务器:
int s, s2, flags, n;
struct sockaddr_un addr;
struct sockaddr_un from;
int from_len;
socklen_t len;
void message_received_helper(int sig){
syslog(LOG_NOTICE, "Works! \n");
}
...
int main(int argc, char *argv[]) {
deamonize();
/* Daemon-specific initialization goes here */
setlogmask (LOG_UPTO (LOG_NOTICE));
openlog ("i_aware", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
syslog (LOG_NOTICE, "Program started by User %d", getuid ());
/*
* This set up is for the non blocking socket that will exist on the server
*/
/* specify the new action for the SIGIO signal */
new_action.sa_handler = message_received_helper;
/* supply the empty set to .sa_mask */
sigemptyset(&new_action.sa_mask);
/* no flags*/
new_action.sa_flags = 0;
/* Associate new_action with the signal SIGIO -
NULL indicates we are not saving any previous action*/
if(sigaction(SIGIO, &new_action, NULL) < 0 ){
syslog(LOG_NOTICE, "Could not associate SIGIO with action...\n");
exit(errno);
}
/*TODO create unix domain socket and listen for a connection*/
if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 ){
syslog(LOG_NOTICE, "Could not create socket: %d \n", errno);
perror("socket");
exit(errno);
}
/* bind socket */
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/dev/foo");
unlink(addr.sun_path);
len = (socklen_t) (strlen(addr.sun_path) + sizeof(addr.sun_family));
if( bind(s, (struct sockaddr *) &addr,len ) == -1){
syslog(LOG_NOTICE, "Could not bind socket %d \n", errno);
perror("bind");
exit(errno);
}
/* listen */
if(listen(s, 1) < 0){
syslog(LOG_NOTICE,"Error on listen: %d \n", errno);
perror("listen");
exit(errno);
}
from_len = sizeof(from);
if(s2 = accept(s, (struct sockaddr *) &from, &from_len ) < 0 ){
syslog(LOG_NOTICE,"Error on accept: %d \n", errno);
perror("accept");
exit(errno);
}
syslog(LOG_NOTICE,"success \n");
/* set the ownership of the socket fd to this process */
syslog(LOG_NOTICE, "F_SETOWN: %d \n" ,fcntl(s2, F_SETOWN, getpid()) );
/*get file access mode and file status flag - no args needed for this F_GETFL comand*/
flags = fcntl(s2, F_GETFL);
syslog(LOG_NOTICE, "F_GETFL: %d \n", flags);
/* Enable non blocking */
syslog(LOG_NOTICE, "F_SETFL: %d \n" , fcntl(s2, F_SETFL, flags | FASYNC));
/*
* At this point the socket described by s2, should be a non blocking socket, when a SIGIO
* is raised upon receipt of data waiting on the socket the method message_received_helper
* will be called
*/
n = recv(s2, str, 1, 0);
syslog(LOG_NOTICE, "Works! \n");
if (n <= 0) {
if (n < 0) syslog(LOG_NOTICE, "recv error: %d", errno);
}
syslog(LOG_NOTICE, "n: %d, s2: %d, str: %s \n", n, s2, str );
if (send(s2, str, n, 0) < 0) {
syslog(LOG_NOTICE, "send: %d", errno);
}
客户:
int s, s2, t, len;
struct sockaddr_un local, remote;
char str[100];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
local.sun_family = AF_UNIX;
strcpy(local.sun_path, SOCK_PATH);
unlink(local.sun_path);
len = strlen(local.sun_path) + sizeof(local.sun_family);
if (bind(s, (struct sockaddr *)&local, len) == -1) {
perror("bind");
exit(1);
}
if (listen(s, 5) == -1) {
perror("listen");
exit(1);
}
for(;;) {
int done, n;
printf("Waiting for a connection...\n");
t = sizeof(remote);
if ((s2 = accept(s, (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected.\n");
done = 0;
do {
n = recv(s2, str, 100, 0);
if (n <= 0) {
if (n < 0) perror("recv");
done = 1;
}
if (!done)
if (send(s2, str, n, 0) < 0) {
perror("send");
done = 1;
}
} while (!done);
close(s2);
两个进程能够通过套接字连接,但客户端向服务器发送数据时不会引发 SIGIO。此外,recv() 函数一直处于阻塞状态,好像我没有做任何事来影响套接字 s2 以使读取不阻塞。
答案1
if(s2 = accept(s, (struct sockaddr *) &from, &from_len ) < 0 )
不正确,应为
if( (s2 = accept(s, (struct sockaddr *) &from, &from_len )) < 0 )
缺少括号使得第一个语句读作s2 = < 0,将 s2 设置为 0;