我正在linux内核中编写一个客户端/服务器(是的。在内核中。它的设计决策已经完成并且最终确定。它不会改变)

服务器从原始套接字读取传入的数据包。这些数据包(原始套接字正在侦听)的传输协议是自定义的,UDP类似。简而言之,我不必监听传入的连接,然后分叉线程来处理该连接。

我必须处理原始套接字上的任何IP数据报。我将继续读取原始套接字上的无限循环中的数据包。在用户级等效程序中,我会创建一个单独的线程并继续侦听传入的数据包。

现在对于内核级服务器,我怀疑是否应该在单独的线程中运行它,因为:

  1. 我认为read()是一个I / O操作。所以在read()内部,内核必须调用schedule()函数来放弃对处理器的控制。因此,在对原始套接字调用read()之后,当前内核活动上下文将被置于保持状态(可能放入休眠队列?),直到数据包可用。当数据包到达时,内核中断上下文将发出正在队列中休眠的读取上下文再次准备好运行的信号。我故意在这里使用'context'而不是'thread'。因此,我不应该要求单独的内核线程。

  2. 另一方面,如果read()没有放弃控件,那么整个内核将被阻止。

  3. 任何人都可以提供有关如何设计服务器的提示吗? 第1点提出的论点的谬误是什么?

有帮助吗?

解决方案

我不确定你是否需要内核中的原始套接字。在内核中你可以添加一个netfilter钩子,或者注册一些其他的(???)接收所有的数据包;这可能是你想要的。

如果你在内核中使用原始套接字,那么你可能需要一个内核线程(即由kernel_thread启动)来调用它上面的read()。但它不一定是内核线程,它可能是一个用户空间线程,只是进行了一个特殊的系统调用或设备调用来调用所需的内核模式例程。

如果你注册了一个钩子,它所调用的上下文可能不应该做太多的处理;我不确切地知道那可能是什么,它可能是一个“下半部分处理程序”。或“tasklet”,无论是什么(这些类型的控制结构不断从一个版本变为另一个版本)。我希望它实际上不是一个中断服务程序。


回答原来的问题:

  1. 是的,sys_read将阻止调用线程,无论是内核线程还是用户空间线程。系统不会挂起。但是,如果调用线程不处于阻塞有意义的状态,内核将会发生混乱(在中断或其他情况下调度)
  2. 是的,你需要在一个单独的线程中执行此操作,不会不会挂起系统。但是,在内核模式下进行系统调用是非常不确定的,尽管它确实有效(等等)。

    但是如果你安装了某种钩子,你就不需要做任何一种。

其他提示

我认为您最好的选择可能是模仿驱动程序的编写方式,将您的服务器视为一个虚拟设备,该虚拟设备位于请求来自的位置之上。示例:鼠标驱动程序接受连续输入,但如果编程正确则不会锁定系统,并且网络适配器可能与您的情况更相似。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top