一、信号驱动。
1、信号驱动原理是什么?
就是使用了系统编程中信号的机制,首先让程序安装SIGIO的信号处理函数,通过监听文件描述符是否产生了SIGIO信号,我们就知道文件描述符有没有数据到达。如果有数据到达(小明这个客人来了),则系统就会产生了SIGIO信号(门铃响了),我们只需要在信号处理函数读取数据即可。
模型:
void fun(int sig)
{
//读取sockfd的数据即可。
}
signal(SIGIO,fun); -> 只要将来收到SIGIO这个信号,就执行fun这个函数
sockfd -> 只要有数据到达sockfd,就会产生一个SIGIO的信号
2、 信号驱动特点以及步骤。
特点: 适用于UDP协议,不适用于TCP协议。
步骤一: 由于不知道数据什么时候会到达,所以需要提前捕捉SIGIO信号。 -> signal()
步骤二: 设置套接字的属主,其实就是告诉这个套接字对应的进程ID是谁。 -> fcntl()
步骤三: 给套接字添加信号触发模式。 -> fcntl()
1)如何设置属主? -> fcntl() -> man 2 fcntl
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
fd: 文件描述符
cmd: F_GETFL (void) -> 获取文件属性
F_SETFL (int) -> 设置文件属性
F_SETOWN (int) -> 设置属性 -> 最后一个参数要填,填进程ID号,一般都是getpid()。
返回值:
成功:文件描述符所有者
失败:-1
例如: fcntl(sockfd,F_SETOWN,getpid()); -> 让sockfd与进程ID绑定在一起。
2)如何添加信号触发模式? -> fcntl() -> man 2 fcntl
int state;
state = fcntl(sockfd,F_GETFL);
state |= O_ASYNC;
fcntl(sockfd,F_SETFL,state);
例题1: 使用信号驱动IO模型写一个UDP协议服务器,实现监听多个客户端给我发送过来的消息。
#include "head.h"
int sockfd;
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
void func(int sig)
{
//将sockfd中的数据读取出来。
char buf[100];
bzero(&cliaddr,sizeof(cliaddr));
bzero(buf,sizeof(buf));
recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&cliaddr,&len);
printf("from cli:%s",buf);
}
int main(int argc,char *argv[]) // ./server 50001
{
//1. 创建UDP套接字
sockfd = socket(AF_INET,SOCK_DGRAM,0);
//2. 绑定IP地址
struct sockaddr_in srvaddr;
bzero(&srvaddr,sizeof(srvaddr));