信号在进程中如何工作的:
1、进程的信号集合如何保存:
每个进程中有sigaction action[64],用于存储所有的信号集合
2、调用signal函数式如何把信号保存到进程里面
每一个信号都有对应的序号,一共有31个信号,如sigio对应的需要是29,则action[28]中存放这sigio信号的相关数据。当有多个相同的信号触发,最近的一次信号会覆盖进去。
3、信号如何发送,进程如何捕获信号
首先注册x(某一个)信号,进程内的action数组下标为x的序号的元素会等待,等到调用kill发送相应的信号之后,action中相应的元素会调用回调函数。与为线程中的条件等待类似。
select
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int maxfdp, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeval *timeout);
不管fd是否在使用,每一次select的数量都是fd的最大值(maxfdp),并且记录fd的三种状态:读(readset),写(writeset),错误(exceptset),设置轮询的时间(timeout)。当timeout没到的时候,进程阻塞在select函数内部。即阻塞最长时间为timeout,若fd状态变化了,select就返回。
poll
#include <poll.h>
int poll(struct pollfd *fdarray, unsigned long nfds, int timeout)
poll将fd的状态放在了一个结构体中(struct pollfd),其他与select相同。
epoll
epoll不会去主动查询fd的状态,而是fd的状态改变时通知epoll。
类比:一个小区寄取快递,小区用户就是io,epoll_ctl可以设置添加用户(fd),用户在蜂巢放快递,epoll是快递员,从蜂巢中去快递
epoll_create(int size) 创建一个epoll句柄,size本来是epoll监听的fd数量,但现在为链表形式,可以扩充fd的数量,不再是固定的fd数量,所以size大于0则可以成功创建epoll(一般取1)。
epoll_ctl() 添加、删除、修改fd
epoll_wait() 设置超时时长
epoll
epoll的et与lt
et是边沿触发
recv buff 从没数据到有数据时才会触发
传输数据较小适合用et+循环读数据
lt是水平触发
recv buff 中只要有数据就会一直触发
传输数据较大适合用lt+一次性读数据
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <errno.h>
#include <sys/epoll.h>
// ./epoll 8080
int main(int argc, char *argv[]) {
if (argc < 2) {
return -1;
}
int port = atoi(argv[1]);
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
return -1;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) {
return -2;
}
if (listen(sockfd, 5) < 0) {
return -3;
}
// epoll opera
int epfd = epoll_create(1);
struct epoll_event ev, events[512] = {0};
ev.events = EPOLLIN;
ev.data.fd = sockfd; //int idx = 2000;
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
//pthread_cond_waittime();
while (1) {
int nready = epoll_wait(epfd, events, 512, -1);
if (nready < -1) {
break;
}
int i = 0;
for (i = 0;i < nready;i ++) {
if (events[i].data.fd == sockfd) {
struct sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(struct sockaddr_in));
socklen_t client_len = sizeof(client_addr);
int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
if (clientfd <= 0) continue;
char str[INET_ADDRSTRLEN] = {0};
printf("recv from %s at port %d\n", inet_ntop(AF_INET, &client_addr.sin_addr, str, sizeof(str)),
ntohs(client_addr.sin_port));
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = clientfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev);
} else {
int clientfd = events[i].data.fd;
char buffer[1024] = {0};
int ret = recv(clientfd, buffer, 1024, 0);
if (ret < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) { //
} else {
}
close(clientfd);
ev.events = EPOLLIN;
ev.data.fd = clientfd;
epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev);
} else if (ret == 0) { //
//
printf("disconnect %d\n", clientfd);
close(clientfd);
ev.events = EPOLLIN;
ev.data.fd = clientfd;
epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev);
} else {
printf("Recv: %s, %d Bytes\n", buffer, ret);
}
}
}
}
}
为epoll引入良好的io管理reactor
epoll 是对io(一个个fd单独管理)进行管理
reactor 是对事件(recv与send事件)用相应的回调函数(recv_cb/send_cb/accept_cb)进行管理
reactor代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <errno.h>
#include <sys/epoll.h>
#define BUFFER_LENGTH 1024
struct sockitem { //
int sockfd;
int (*callback)(int fd, int events, void *arg);
char recvbuffer[BUFFER_LENGTH]; //
char sendbuffer[BUFFER_LENGTH];
int rlength;
int slength;
};
// mainloop / eventloop --> epoll -->
struct reactor {
int epfd;
struct epoll_event events[512];
};
struct reactor *eventloop = NULL;
int recv_cb(int fd, int events, void *arg);
int send_cb(int fd, int events, void *arg) {
struct sockitem *si = (struct sockitem*)arg;
send(fd, si->sendbuffer, si->slength, 0); //
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET;
//ev.data.fd = clientfd;
si->sockfd = fd;
si->callback = recv_cb;
ev.data.ptr = si;
epoll_ctl(eventloop->epfd, EPOLL_CTL_MOD, fd, &ev);
}
// ./epoll 8080
int recv_cb(int fd, int events, void *arg) {
//int clientfd = events[i].data.fd;
struct sockitem *si = (struct sockitem*)arg;
struct epoll_event ev;
//char buffer[1024] = {0};
int ret = recv(fd, si->recvbuffer, BUFFER_LENGTH, 0);
if (ret < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) { //
return -1;
} else {
}
ev.events = EPOLLIN;
//ev.data.fd = fd;
epoll_ctl(eventloop->epfd, EPOLL_CTL_DEL, fd, &ev);
close(fd);
free(si);
} else if (ret == 0) { //
//
printf("disconnect %d\n", fd);
ev.events = EPOLLIN;
//ev.data.fd = fd;
epoll_ctl(eventloop->epfd, EPOLL_CTL_DEL, fd, &ev);
close(fd);
free(si);
} else {
printf("Recv: %s, %d Bytes\n", si->recvbuffer, ret);
si->rlength = ret;
memcpy(si->sendbuffer, si->recvbuffer, si->rlength);
si->slength = si->rlength;
struct epoll_event ev;
ev.events = EPOLLOUT | EPOLLET;
//ev.data.fd = clientfd;
si->sockfd = fd;
si->callback = send_cb;
ev.data.ptr = si;
epoll_ctl(eventloop->epfd, EPOLL_CTL_MOD, fd, &ev);
}
}
int accept_cb(int fd, int events, void *arg) {
struct sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(struct sockaddr_in));
socklen_t client_len = sizeof(client_addr);
int clientfd = accept(fd, (struct sockaddr*)&client_addr, &client_len);
if (clientfd <= 0) return -1;
char str[INET_ADDRSTRLEN] = {0};
printf("recv from %s at port %d\n", inet_ntop(AF_INET, &client_addr.sin_addr, str, sizeof(str)),
ntohs(client_addr.sin_port));
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET;
//ev.data.fd = clientfd;
struct sockitem *si = (struct sockitem*)malloc(sizeof(struct sockitem));
si->sockfd = clientfd;
si->callback = recv_cb;
ev.data.ptr = si;
epoll_ctl(eventloop->epfd, EPOLL_CTL_ADD, clientfd, &ev);
return clientfd;
}
int main(int argc, char *argv[]) {
if (argc < 2) {
return -1;
}
int port = atoi(argv[1]);
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
return -1;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) {
return -2;
}
if (listen(sockfd, 5) < 0) {
return -3;
}
eventloop = (struct reactor*)malloc(sizeof(struct reactor));
// epoll opera
eventloop->epfd = epoll_create(1);
struct epoll_event ev;
ev.events = EPOLLIN;
struct sockitem *si = (struct sockitem*)malloc(sizeof(struct sockitem));
si->sockfd = sockfd;
si->callback = accept_cb;
ev.data.ptr = si;
epoll_ctl(eventloop->epfd, EPOLL_CTL_ADD, sockfd, &ev);
while (1) {
int nready = epoll_wait(eventloop->epfd, eventloop->events, 512, -1);
if (nready < -1) {
break;
}
int i = 0;
for (i = 0;i < nready;i ++) {
if (eventloop->events[i].events & EPOLLIN) {
//printf("sockitem\n");
struct sockitem *si = (struct sockitem*)eventloop->events[i].data.ptr;
si->callback(si->sockfd, eventloop->events[i].events, si);
}
if (eventloop->events[i].events & EPOLLOUT) {
struct sockitem *si = (struct sockitem*)eventloop->events[i].data.ptr;
si->callback(si->sockfd, eventloop->events[i].events, si);
}
}
}
}