关于套接字的疑问

2016-03-25 09:55:54 +08:00
 ubear1991

一直有个疑问,关于 IO 多路复用的。

假设应用程序进程监听在 localhost:80 。这实际上是一个套接字吧。 那么,有需要用 IO 多路复用么?监听在多个套接字上才有必要用 IO 多路复用吧。

不知道哪出了问题,没想明白。请有明白的解释一下。 谢谢。

3005 次点击
所在节点    问与答
40 条回复
SoloCompany
2016-03-25 10:31:42 +08:00
直接说 socket 不行吗
不要把 server socket 和 client socket 的概念搞混了
ubear1991
2016-03-25 10:32:04 +08:00
查资料看到了原来监听之后 accept 会生成新的套接字。
ubear1991
2016-03-25 10:33:42 +08:00
@SoloCompany 嗯,大概明白了。我以为就一种套接字。
ubear1991
2016-03-25 10:51:55 +08:00
又有一个问题。当一个链接建立之后,客户端的数据还是发往 80 端口么,或者是发往新的套接字的端口?
DuckJK
2016-03-25 11:04:51 +08:00
我查了下资料:
服务端 socket 流程是这样的:
先创建 socket()---bind()---listen()--循环 accept()
在 accept 的时候可能会产生阻塞(blocking),,所以又有一种叫做非阻塞(non-blocking),就是在等待客户端访问的时候, CPU 处理其他的事情,这种情况下如果要返回处理客户端,继续要不断的轮询,会浪费 CPU 的时间。然后又有一种新的方法比如(select 、 polll)可以同时监控多个 socket 进行轮询,比如哪些 socket 可以读取,哪些可以写入,这种是最基本的多路复用。

以上可能有错误,我查到的是这么个情况。参考资料:

https://translate.googleusercontent.com/translate_c?depth=1&hl=zh-CN&prev=search&rurl=translate.google.com.sg&sl=zh-TW&u=http://beej-zhtw.netdpi.net/07-advanced-technology/7-2-select&usg=ALkJrhg0zwDET71E2ri1ObOL_Xb3et8b8w

http://www.keakon.net/2011/09/28/%E5%85%B3%E4%BA%8Esocket%E7%9A%84%E4%B8%80%E4%BA%9B%E5%88%9D%E6%AD%A5%E7%A0%94%E7%A9%B6

http://www.cnblogs.com/Anker/p/3254269.html
wy315700
2016-03-25 11:05:29 +08:00
端口 != 套接字
ubear1991
2016-03-25 11:42:11 +08:00
@DuckJK

我有一点不理解。 accept 就算是阻塞了,服务器的 CPU 不也是在干活,比如处理其他进程。 accept 进程在阻塞队列里等待唤醒事件。

这里面的非阻塞只并不阻塞这个进程,而 CPU 也在处理比如说其他 socket 的通信事件?
hitmanx
2016-03-25 12:35:30 +08:00
@ubear1991 对的,进程阻塞以后操作系统会把这个进程设为 blocked ,依照唤醒需要的资源丢到对应的队列里,以便在将来资源有的时候(在这个例子里就是 server 端端口收到io的时候)唤醒。然后会在状态为 ready 的进程队列里会挑选一个进程运行,并把它的状态设置为 running 。
ubear1991
2016-03-25 12:43:31 +08:00
@hitmanx

这是阻塞的方式吧?还有非阻塞。
mhycy
2016-03-25 12:54:32 +08:00
<论底层基础的重要性>

首先, Accept 这个过程之前必定有一次 bind 的操作
这个操作是通知内核,进程要绑定某个端口,以后进程会使用这个端口进行通讯
然后在 listen 的时候开启一个队列, accept 只是读取这个队列。
如果是阻塞状态,那么队列没数据自然就等待在那了。
如果有新连接进入,那么内核会进行预处理
(判断是否合法,如果合法就分配资源生成一个 socket ,扔到队列)
自然而然的,队列有数据了,就会通知上层的应用进行调度。

(至于这个队列在底层的原理以及 CPU 在等待的时候刚啥,这个涉及到硬件层面的调度,例如中断。。)

而一个链路的唯一标记是包含地址在内的四元组( local_ip, local_port, remote_ip, remote_port )
bind 的过程只是定义了本地的 local_ip, local_port 。
远端而来的 ip/端口是不固定的
hitmanx
2016-03-25 12:55:36 +08:00
@ubear1991 我的回复是针对你问阻塞对于 CPU (操作系统)、进程是什么关系。 V2EX 上 at 人看不出 at 的是哪一楼这是个问题。关于阻塞和非阻塞的 socket 的用法应该能搜到大量的教程和资源。
msg7086
2016-03-25 13:00:24 +08:00
顺便你可以多个进程监听同一个端口。
DuckJK
2016-03-25 13:12:51 +08:00
@ubear1991 阻塞简单来说就是 “ sleep 的技术术语”,我发给你的第一个链接里面有,第三个链接里面会把它具体化容易理解。
jy01264313
2016-03-25 13:46:46 +08:00
看看五个 IO 模型。
iMouseWu
2016-03-25 16:01:39 +08:00
@mhycy 我的理解是。如果按照这种 accept()创建了 socket 连接以后,还会有一个接受信息的阻塞过程(数据从内核缓冲区到用户缓冲器)。而 I/O 多路复用拿到的连接不需要这一阻塞步骤,因为内核会把数据从内核缓冲区到用户缓冲器拷贝完成以后才会通知 select 的线程。
可以这么理解嘛?
ubear1991
2016-03-25 16:30:03 +08:00
@iMouseWu

unix 网络编程里面说 这个是异步 I/O 。
DuckJK
2016-03-25 16:48:09 +08:00
@iMouseWu 我认为你说的这种是 I/O 多路复用搭配 non-blocking 的问题, https://www.zhihu.com/question/37271342 ,里面的回答是这样的:

Under Linux, select() may report a socket file descriptor as "ready for reading", while nevertheless a subsequent read blocks. This could for example happen when
data has arrived but upon examination has wrong checksum and is discarded. There may be other circumstances in which a file descriptor is spuriously reported as
ready. Thus it may be safer to use O_NONBLOCK on sockets that should not block.

里面说的是 select 和 read , select 和 read 是两个独立的系统调用,当 select 可读的时候, read 不一定可读。我没有查 accept 的 man 手册,但是我觉得 accept 也是这样的。(我感觉 accept 这句话有问题)

最后结果就是 I/O 多路复用搭配 non-blocking 。至于你说的数据从内核缓冲区 copy 到用户缓冲区,这个我不太了解。
DuckJK
2016-03-25 16:56:22 +08:00
@iMouseWu http://kenby.iteye.com/blog/1159621 我找到一个 tornado 的例子,里面是 accept 完成之后返回客户端的 socket ,然后创建了两个缓冲区,_read_buffer 和_write_buffer
iMouseWu
2016-03-25 16:59:31 +08:00
@ubear1991 抱歉,我记错了。这个是算异步的,阻塞应该是发生在内核到数据完成准备这个阶段
iMouseWu
2016-03-25 17:27:28 +08:00
@DuckJK 不好意思,前面的内核缓存区和用户缓存区有误感谢 @ubear1991 指出,具体看 19 楼。
我一开始也是如你 17 楼所说的去理解,select 和 accept 可读,read 不一定可读,但是如果这样子的话。我的理解是:
1.直接 accept,为每个 accept 的 socket 创建一个线程处理这个 socket,在这些线程里面可能会 read 阻塞
2.I/O 多路复用,select 出来一个 socket,创建一个线程处理这个 socket,在这些线程里面可能会 read 阻塞
所以感觉 I/O 多路复用没有优势。
望指正

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/266221

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX