我对C中的事件驱动编程非常感兴趣,特别是使用套接字,因此我将花一些时间来完成我的研究。C中的事件驱动模型
我们假设我想要构建一个包含大量文件和网络I/O的程序,就像客户机/服务器应用程序一样,基本上第一个问题是这个模型背后的原理是什么。在正常编程中,我会产生新的进程,一个进程怎么能够实际上服务于许多其他的请求。例如,有一些Web服务器可以处理连接,而无需创建线程或其他进程,只需一个主进程。
我知道这很复杂,但它总是很好,至少知道这些编程的基础结构如何。
我对C中的事件驱动编程非常感兴趣,特别是使用套接字,因此我将花一些时间来完成我的研究。C中的事件驱动模型
我们假设我想要构建一个包含大量文件和网络I/O的程序,就像客户机/服务器应用程序一样,基本上第一个问题是这个模型背后的原理是什么。在正常编程中,我会产生新的进程,一个进程怎么能够实际上服务于许多其他的请求。例如,有一些Web服务器可以处理连接,而无需创建线程或其他进程,只需一个主进程。
我知道这很复杂,但它总是很好,至少知道这些编程的基础结构如何。
您一定要阅读以下内容:http://www.kegel.com/c10k.html。该页面是事件驱动和异步技术的完美概述。
但是,一个快速&肮脏的答案:事件驱动既不是非阻塞,也不是异步。事件驱动意味着进程将监视其文件描述符(和套接字),并且仅当某些事件发生在某些描述符(事件是:收到数据,错误,变为可写,...)时才动作。
BSD套接字具有“select()”功能。被调用时,操作系统将监视描述符,并在其中一个描述符发生某些事件时立即返回进程。
但是,上面的网站有更好的描述(以及有关不同API的详细信息)。
它实际上是非常平台具体如何工作。
如果你的Linux系统这真的不是很难,虽然,你只需要使用“叉”像下面会做的伎俩产卵的过程副本上运行:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet.h>
#include <signal.h>
#include <unistd.h>
int main()
{
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_Address.sin_port = htons(1234);
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
listen(server_sockfd, 5);
signal(SIGCHLD, SIG_IGN);
while(1)
{
char ch;
printf("Server Waiting\n");
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len)
// Here's where we do the forking, if you've forked already then this will be the child running, if not then your still the parent task.
if(fork() == 0)
{
// Do what ever the child needs to do with the connected client
read(client_sockfd, &ch, 1);
sleep(5); // just for show :-)
ch++;
write(client_sockfd, &ch, 1);
close(client_sockfd);
exit(0);
}
else
{
// Parent code here, close and loop for next connection
close(client_sockfd);
}
}
}
您可能我不得不小心操作那些代码,现在我还没有在Linux机器附近进行测试编译,而且我几乎从内存中输入了它。
但是使用fork是在基于Linux/Unix的系统下在C中执行此操作的标准方式。在Windows下这是一个非常不同的故事,我不能完全记住所有需要的代码(我习惯于在C#中编写代码的方式),但设置套接字几乎是一样的您需要使用'Winsock'API以获得更好的兼容性。
你可以(我认为是这样)仍然使用标准Berkeley套接字在Windows下,但它充满陷阱和孔,适用于Windows的Winsock这是一个良好的开端:
http://tangentsoft.net/wskfaq/
至于我我也知道,如果你使用Winsock,它有一些东西来帮助产生和多客户端,但是我个人通常只是分离出一个单独的线程,然后复制套接字连接,然后返回到收听我的服务器。
这种TCP服务器/客户端可以通过使用select(2)
调用和非阻塞套接字来实现。
使用非阻塞套接字比阻塞套接字更为棘手。
实施例:
connect
调用通常返回-1立即和设置errno EINPROGRESS
非阻塞插座一起使用时。在这种情况下,您应该使用select
等待连接打开或失败。 connect
也可能返回0.如果您创建到本地主机的连接,则可能发生这种情况。 这样你可以服务其他套接字,而一个套接字打开TCP连接。
“这是什么模式背后的理念是”
事件驱动方式有没有“监控”,但事件本身发起行动。
通常这是由中断引发的,该中断是从外部设备向系统发出的信号,或者(在软件中断的情况下)异步过程。
https://en.wikipedia.org/wiki/Interrupt
延伸阅读似乎是在这里:
https://docs.oracle.com/cd/E19455-01/806-1017/6jab5di2m/index.html#sockets-40 - “中断驱动套接字I/O”
而且http://cs.baylor.edu/~donahoo/practical/CSockets/textcode.html有中断驱动套接字的一些例子,以及其他套接字编程示例。
如果你打算做任何linux套接字的东西,我会建议Beejs指南在这里http://beej.us/guide/bgnet/ – mathematician1975
感谢您的建议,这本书解释或包含任何形式的事件驱动编程参考? – iNDicator
目前还不清楚你在问什么,但你可以先阅读libevent的文档。 – Artefacto