connect()
Client 0 -------------
Client 1 ---------- \ accept()
. \ ------> +-------------+
. ---------> | TCP server | <--- Dispatcher process.
. ---------> |-------------|
Client N ----------/ | IPC server |
+-------------+
/ / \
/ / \ <--- Pass file descriptor
---------------------/ / \ to less stressed worker.
/ / \
/ / \
| | |
+-------------+ +-------------+ +-------------+ Workers are processes,
| Worker #0 | | Worker #1 | ... | Worker #M | and use epoll to
+-------------+ +-------------+ +-------------+ send(), recv().
| | |
| #0 | #1 | #N
Shared | memory Shared | memory Shared | memory
+-------------+ +-------------+ +-------------+
| rw_lock | | rw_lock | | rw_lock |
|-------------| |-------------| |-------------|
| User #0 | | User #1 | | User #2 |
|-------------| |-------------| |-------------|
| User #3 | | User #4 | ... | User #5 |
|-------------| |-------------| |-------------|
| . | | . | | . |
| . | | . | | . |
| . | | . | | . |
+-------------+ +-------------+ +-------------+
The workers communicate with each other through the IPC socket server.
Imagine the following situation:
Worker #0 have 100 succesful login, so it may have to send a userlist of
one hundred, but meanwhile in Worker #1 (for example) User #1 send message:
"bye", and disconnect from the server. So, what is happening:
Worker #0 epoll list: Worker #0 reaction:
- recv() - send(nicklist)
- recv() - send(nicklist)
- ... - ...
Worker #0 lock SHM #0, SHM #1, ..., SHM #M, and assemble the user list, and
send out.
Meanwhile when try to lock SHM #1, dont succesful, because Worker #1 locked
it for write: remove the disconnected client. (And Worker #1 send two messages
to IPC server: message from user (bye), client (xy) is disconnected).
So, now Worker #0 epoll list:
Worker #0 epoll list: Worker #0 reaction:
- TCP recv() - send(nicklist)
- TCP recv() - send(nicklist)
- ... - ...
- IPC recv() - send_broadcast_to_my_clients(xy msg: bye)
- IPC recv() - send_broadcast_to_my_clients(xy disconnected)
And what the clients are look:
- I have a nicklist, where User #1 does not exist, but he say: "bye", and quit.
(Is he a ghost?)
The question is: how can I sync that?
问题是:我该如何同步?
I've been thinking a lot about what would be the solution.
我一直在思考什么是解决方案。
I got this:
我懂了:
Don't use shared memory, all worker store a global userlist (what is syncronized by IPC socket), but this solution is too memory-intensive.
不要使用共享内存,所有工作者都存储全局用户列表(IPC套接字同步的内容),但此解决方案过于占用大量内存。
1 个解决方案
#1
1
It is very difficult to give you a sensible answer, as you've already decided on things that make little sense. Your question is a loaded foot-gun, and any answer will be deficient.
很难给你一个明智的答案,因为你已经决定了没有意义的事情。你的问题是一个装满脚的枪,任何答案都是不足的。
For example, this is all incorrect:
例如,这都是不正确的:
Meanwhile when try to lock SHM #1, dont succesful, because Worker #1 locked it for write: remove the disconnected client. (And Worker #1 send two messages to IPC server: message from user (bye), client (xy) is disconnected).
同时,当试图锁定SHM#1时,不要成功,因为Worker#1将其锁定以进行写入:删除断开连接的客户端。 (而工人#1向IPC服务器发送两条消息:来自用户(再见)的消息,客户端(xy)被断开)。
You don't "try" to lock, you lock. The locking operation will block until it can be satisfied. Ergo, no issues similar to the ones you described.
你没有“试图”锁定,你锁定。锁定操作将阻塞,直到可以满足为止。因此,没有与您描述的问题类似的问题。
This means that you do need to minimize the time you keep the structure locked, especially for write locks. For example, you never send or receive data while keeping the structure locked: you copy the necessary parts from the structure to a temporary (dynamically allocated) buffer, release the lock, and then send the (messages based on the) buffer contents.
这意味着您确实需要最小化保持结构锁定的时间,尤其是对于写锁定。例如,在保持结构锁定的同时永远不会发送或接收数据:将必要的部分从结构复制到临时(动态分配)缓冲区,释放锁定,然后发送(基于缓冲区内容的消息)缓冲区内容。
If you already have the shared memory, why would you use an IPC server? The shared memory segment is already a fully-featured IPC mechanism, so why would you make everything more complex for no gain? The original process should only manage the child processes.
如果您已有共享内存,为什么要使用IPC服务器?共享内存段已经是一个功能齐全的IPC机制,那么为什么你会让一切变得更加复杂而无法获得收益呢?原始进程应该只管理子进程。
Finally, you've already decided to use processes, while this design is much more workable with threads (pthreads). For example, if you were using threads, each worker could send targeted messages to any client directly, if the shared memory contains also the file descriptors.
最后,您已经决定使用进程,而这种设计更适用于线程(pthreads)。例如,如果您使用线程,则每个工作人员可以直接向任何客户端发送目标消息,如果共享内存还包含文件描述符。
You have encountered problems, and are asking how to fix a solution path you have already chosen. That is wrong. You should ask what is wrong with your design as you are having difficulty in implementing it, and how to fix your design.
您遇到了问题,并询问如何修复已选择的解决方案路径。那是错的。你应该问你的设计有什么问题,因为你很难实现它,以及如何修复你的设计。
#1
1
It is very difficult to give you a sensible answer, as you've already decided on things that make little sense. Your question is a loaded foot-gun, and any answer will be deficient.
很难给你一个明智的答案,因为你已经决定了没有意义的事情。你的问题是一个装满脚的枪,任何答案都是不足的。
For example, this is all incorrect:
例如,这都是不正确的:
Meanwhile when try to lock SHM #1, dont succesful, because Worker #1 locked it for write: remove the disconnected client. (And Worker #1 send two messages to IPC server: message from user (bye), client (xy) is disconnected).
同时,当试图锁定SHM#1时,不要成功,因为Worker#1将其锁定以进行写入:删除断开连接的客户端。 (而工人#1向IPC服务器发送两条消息:来自用户(再见)的消息,客户端(xy)被断开)。
You don't "try" to lock, you lock. The locking operation will block until it can be satisfied. Ergo, no issues similar to the ones you described.
你没有“试图”锁定,你锁定。锁定操作将阻塞,直到可以满足为止。因此,没有与您描述的问题类似的问题。
This means that you do need to minimize the time you keep the structure locked, especially for write locks. For example, you never send or receive data while keeping the structure locked: you copy the necessary parts from the structure to a temporary (dynamically allocated) buffer, release the lock, and then send the (messages based on the) buffer contents.
这意味着您确实需要最小化保持结构锁定的时间,尤其是对于写锁定。例如,在保持结构锁定的同时永远不会发送或接收数据:将必要的部分从结构复制到临时(动态分配)缓冲区,释放锁定,然后发送(基于缓冲区内容的消息)缓冲区内容。
If you already have the shared memory, why would you use an IPC server? The shared memory segment is already a fully-featured IPC mechanism, so why would you make everything more complex for no gain? The original process should only manage the child processes.
如果您已有共享内存,为什么要使用IPC服务器?共享内存段已经是一个功能齐全的IPC机制,那么为什么你会让一切变得更加复杂而无法获得收益呢?原始进程应该只管理子进程。
Finally, you've already decided to use processes, while this design is much more workable with threads (pthreads). For example, if you were using threads, each worker could send targeted messages to any client directly, if the shared memory contains also the file descriptors.
最后,您已经决定使用进程,而这种设计更适用于线程(pthreads)。例如,如果您使用线程,则每个工作人员可以直接向任何客户端发送目标消息,如果共享内存还包含文件描述符。
You have encountered problems, and are asking how to fix a solution path you have already chosen. That is wrong. You should ask what is wrong with your design as you are having difficulty in implementing it, and how to fix your design.
您遇到了问题,并询问如何修复已选择的解决方案路径。那是错的。你应该问你的设计有什么问题,因为你很难实现它,以及如何修复你的设计。