1

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

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

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

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

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

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

谁能提供有关如何设计服务器的提示?第 1 点提出的论点的谬误是什么?

4

2 回答 2

2

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

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

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


在回答你原来的问题:

  1. 是的, sys_read 将阻塞调用线程,无论是内核线程还是用户空间线程。系统不会挂起。但是,如果调用线程不处于阻塞有意义的状态,内核将恐慌(调度中断或其他东西)

是的,您需要在单独的线程中执行此操作,不,它不会挂起系统。然而,在内核模式下进行系统调用是非常不确定的,尽管它确实有效(有点)。

但是如果你安装了某种钩子,你就不需要这样做了。

于 2009-03-05T22:23:00.313 回答
0

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

于 2009-03-05T16:23:54.390 回答