多個進程同時監聽一個端口,如果外部有連接,多個進程通過內核實現的競爭機制,就會有一個被喚醒。
直接上代碼:
int main()
{
// 創建服務器
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(9988);
addr.sin_addr.s_addr = INADDR_ANY;
int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
if(ret < 0)
{
perror("bind");
return 1;
}
listen(fd, 20);
int process_count = 20;
int isParent = 1;
for(int i=0; i<process_count; ++i)
{
pid_t pid = fork();
if(pid == 0)
{
isParent = 0;
break;
}
}
// 服務器文件描述符被複制了5份
// 以下代碼被執行6次,每個進程都會執行該代碼
int epollfd = epoll_create(512);
struct epoll_event ev;
ev.data.fd = fd;
ev.events = EPOLLIN;
// 服務器加入到epoll
epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
while(1)
{
struct epoll_event out_ev[8];
int ret = epoll_wait(epollfd, out_ev, 8, 2000);
if(ret > 0)
{
for(int i=0; i<ret; ++i)
{
struct epoll_event* p = &out_ev[i];
if(p->data.fd == fd)
{
int newfd = accept(fd, NULL, NULL);
ev.data.fd = newfd;
epoll_ctl(epollfd, EPOLL_CTL_ADD, newfd, &ev);
}
else
{
char buf[1024];
int ret = recv(p->data.fd, buf, sizeof(buf), 0);
if(ret > 0)
printf("%s\n", buf);
else // ret <= 0
{
close(p->data.fd);
}
}
}
}
}
if(isParent)
{
for(int i=0; i<process_count; ++i)
{
wait(NULL);
}
}
}