问题描述
在套接字编程中,您创建一个侦听套接字,然后对于每个连接的客户端,您都会获得一个普通的流套接字,您可以使用它来处理客户端的请求.操作系统在后台管理传入连接队列.
In socket programming, you create a listening socket and then for each client that connects, you get a normal stream socket that you can use to handle the client's request. The OS manages the queue of incoming connections behind the scenes.
两个进程不能同时绑定到同一个端口 - 无论如何,默认情况下.
Two processes cannot bind to the same port at the same time - by default, anyway.
我想知道是否有办法(在任何众所周知的操作系统上,尤其是 Windows 上)启动一个进程的多个实例,以便它们都绑定到套接字,从而有效地共享队列.每个流程实例都可以是单线程的;它只会在接受新连接时阻塞.当客户端连接时,空闲流程实例之一将接受该客户端.
I'm wondering if there's a way (on any well-known OS, especially Windows) to launch multiple instances of a process, such that they all bind to the socket, and so they effectively share the queue. Each process instance could then be single threaded; it would just block when accepting a new connection. When a client connected, one of the idle process instances would accept that client.
这将允许每个进程有一个非常简单的单线程实现,除非通过显式共享内存,否则不共享任何内容,并且用户将能够通过启动更多实例来调整处理带宽.
This would allow each process to have a very simple, single-threaded implementation, sharing nothing unless through explicit shared memory, and the user would be able to adjust the processing bandwidth by starting more instances.
有这样的功能吗?
对于那些问为什么不使用线程?"的人显然线程是一种选择.但是对于单个进程中的多个线程,所有对象都是可共享的,并且必须非常小心以确保对象不是不共享的,或者一次只对一个线程可见,或者是绝对不可变的,并且大多数流行的语言和运行时缺乏管理这种复杂性的内置支持.
For those asking "Why not use threads?" Obviously threads are an option. But with multiple threads in a single process, all objects are shareable and great care has to be taken to ensure that objects are either not shared, or are only visible to one thread at a time, or are absolutely immutable, and most popular languages and runtimes lack built-in support for managing this complexity.
通过启动少量相同的工作进程,您将获得一个并发系统,其中默认没有共享,从而更容易构建正确且可扩展的实现.
By starting a handful of identical worker processes, you would get a concurrent system in which the default is no sharing, making it much easier to build a correct and scalable implementation.
推荐答案
您可以在 Linux 甚至 Windows 中的两个(或多个)进程之间共享一个套接字.
You can share a socket between two (or more) processes in Linux and even Windows.
在 Linux(或 POSIX 类型操作系统)下,使用 fork()
将导致分叉的子进程拥有父进程的所有文件描述符的副本.任何它没有关闭的将继续共享,并且(例如使用 TCP 侦听套接字)可用于为客户端accept()
新套接字.这是运行的服务器数量,在大多数情况下包括 Apache.
Under Linux (Or POSIX type OS), using fork()
will cause the forked child to have copies of all the parent's file descriptors. Any that it does not close will continue to be shared, and (for example with a TCP listening socket) can be used to accept()
new sockets for clients. This is how many servers, including Apache in most cases, work.
在 Windows 上,同样的事情基本上是正确的,除了没有 fork()
系统调用,所以父进程需要使用 CreateProcess
或其他东西来创建子进程进程(当然可以使用相同的可执行文件)并且需要传递给它一个可继承的句柄.
On Windows the same thing is basically true, except there is no fork()
system call so the parent process will need to use CreateProcess
or something to create a child process (which can of course use the same executable) and needs to pass it an inheritable handle.
使侦听套接字成为可继承的句柄不是一项完全微不足道的活动,但也不是太棘手.DuplicateHandle()
需要用于创建重复句柄(但仍在父进程中),它将在其上设置可继承标志.然后,您可以将 STARTUPINFO
结构中的句柄作为 STDIN
、OUT
或 ERR
提供给 CreateProcess 中的子进程> 句柄(假设您不想将其用于其他任何用途).
Making a listening socket an inheritable handle is not a completely trivial activity but not too tricky either. DuplicateHandle()
needs to be used to create a duplicate handle (still in the parent process however), which will have the inheritable flag set on it. Then you can give that handle in the STARTUPINFO
structure to the child process in CreateProcess as a STDIN
, OUT
or ERR
handle (assuming you didn't want to use it for anything else).
阅读 MDSN 库,看来 WSADuplicateSocket
是一种更健壮或更正确的机制;这仍然很重要,因为父/子进程需要确定哪些句柄需要通过某种 IPC 机制复制(尽管这可能像文件系统中的文件一样简单)
Reading the MDSN library , it appears that WSADuplicateSocket
is a more robust or correct mechanism of doing this; it is still nontrivial because the parent/child processes need to work out which handle needs to be duplicated by some IPC mechanism (although this could be as simple as a file in the filesystem)
澄清:
回答 OP 的原始问题,不,多个进程不能 bind()
;只是原来的父进程会调用bind()
、listen()
等,子进程只会通过accept()
、send()
, recv()
等
In answer to the OP's original question, no, multiple processes cannot bind()
; just the original parent process would call bind()
, listen()
etc, the child processes would just process requests by accept()
, send()
, recv()
etc.
这篇关于有没有办法让多个进程共享一个监听套接字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!