为啥在 TCP 中使用 bind()?为啥它只用在服务器端而不用在客户端?

Posted

技术标签:

【中文标题】为啥在 TCP 中使用 bind()?为啥它只用在服务器端而不用在客户端?【英文标题】:Why is bind() used in TCP? Why is it used only on server side and not in client side?为什么在 TCP 中使用 bind()?为什么它只用在服务器端而不用在客户端? 【发布时间】:2012-09-27 14:44:35 【问题描述】:

我想知道 TCP 中 bind() 的确切功能。将本地地址“绑定”到套接字是什么意思?如果它为套接字分配一个端口号,那么我们为什么不在客户端使用它呢?我知道该端口是由操作系统在客户端自动分配的,但我并没有全面了解这一切是如何工作的。

在bind()之后,我们监听()。绑定与listen() 有什么关系? listen() 会知道 bind() 已经执行了吗?如果是这样,bind() 会进行哪些更改以使其为人所知?我的意思是,成功执行返回零有什么帮助?

我已经阅读了许多定义,但我无法详细了解所有这些。因此,如果有人可以向我解释一下,我将不胜感激。

【问题讨论】:

【参考方案1】:

它分配“本地”端的端口号。

对于服务器套接字,这是最终的方法 - 这正是所需要的:例如,将您的套接字绑定到 Web 服务器的端口 80。

但是,对于客户端套接字,本地地址和端口通常并不重要。所以你不要bind()。如果服务器限制其客户端可能具有某个端口号,或者端口号超出给定范围,您也可以在客户端使用bind()

另一方面,您也可以在尚未调用bind() 的套接字上使用listen()(实际上我对此不确定,但这是有道理的)。在这种情况下,您的服务器端口将是随机的,并且服务器进程将通过不同的方式将其端口传递给客户端。想象一个“双连接”协议,例如 FTP,其中有一个控制连接和一个数据连接。数据连接侦听的端口是完全任意的,但必须与另一端通信。所以使用“自动确定的端口”进行通信。

Python 中的一个例子:

import socket
s = socket.socket() # create your socket
s.listen(10) # call listen without bind
s.getsockname() Which random port number did we get?
# here results in ('0.0.0.0', 61372)

s2 = socket.socket() # create client socket
s2.connect(('localhost', 61372)) # connect to the one above
s3, x = s.accept() # Python specific use; s3 is our connected socket on the server side
s2.getpeername()
# gives ('127.0.0.1', 61372)
s2.getsockname()
# gives ('127.0.0.1', 54663)
s3.getsockname()
# gives ('127.0.0.1', 61372), the same as s2.getpeername(), for symmetry
s3.getpeername()
#gives ('127.0.0.1', 54663), the same as s2.getsockname(), for symmetry
#test the connection
s2.send('hello')
print s3.recv(10)

【讨论】:

这个答案不完整,因为它还负责通过 IP 地址监听哪些网络接口,例如0.0.0.0【参考方案2】:

bind() 定义连接的本地端口和接口地址。 connect() 执行隐含的 bind("0.0.0.0", 0) 如果之前没有完成(零被视为“任何”)。

对于传出连接,这通常是可以接受和首选的。操作系统将简单地绑定到“所有接口”并选择一些高编号的未使用端口。如果服务器期望您来自特定端口或端口范围,您只需要在客户端上绑定。有些服务只允许来自小于 1024 的端口号的连接,这些只能由超级用户绑定,尽管现在每个人都控制着自己的机器,这并不意味着什么。

对于传入连接,您必须绑定到已知端口,以便客户端知道在哪里与您联系。一旦他们这样做了,他们就为服务器提供了他们的本地地址/端口,以便通信可以双向流动。 listen() 只能在 bind() 调用后工作。

所有套接字都必须绑定,无论是 UDP、TCP 还是其他。只是并不总是明确地完成。

【讨论】:

"listen() 只能在bind() 调用后工作。"不,正如您在my example 中看到的那样。 如果它有效,那么bind() 是隐式的,它会选择一个绑定到所有接口的半随机端口号。这通常没有用(尽管有极少数例外)。 Brian White 是正确的,因为 connect() 进行了隐式绑定(否则,如果不先在本地保留资源,内核将不知道如何连接)。【参考方案3】:

它将一个套接字“绑定”到一个地址,否则它不知道它应该监听哪个地址(ip-地址/端口对)。

bind 也可以在客户端使用。一个例子是在一台有多个网卡连接到同一个网络的计算机上,但客户端只想被视为来自一个特定的网络地址。

绑定不仅用于 TCP 套接字,还用于 UDP 套接字以及其他协议。

【讨论】:

我相信您在描述客户端示例时指的是“绑定”。这与 IP 地址/端口号绑定不同。网络接口卡 (NIC) 绑定(也称为组合)使您能够将两个 NIC 连接为一个物理设备,以便它们显示为一个接口。【参考方案4】:

我知道这是一个老问题,但我有一个新答案:)

您可能希望连接到每个 ip 只允许有限数量的传入连接的服务器。

如果您有多个网络接口卡(因此有多个可能的传出 ips 来连接),您可以使用 bind(),手动循环通过每个 ips,以平衡您的连接,因此有几次其他情况下允许的许多连接。

要获取您的接口和 ips 列表,请参阅this 答案。

【讨论】:

以上是关于为啥在 TCP 中使用 bind()?为啥它只用在服务器端而不用在客户端?的主要内容,如果未能解决你的问题,请参考以下文章

为啥socket后,客户端可以不适用bind函数

bind为啥性能不好

为啥 Butterknife @Bind 在发布版本中失败(在 proguard 之后)

如果在多个系统调用中完成,为啥 TCP 套接字会变慢?

为啥我不能只用前向声明 C++ 声明一个类的静态成员?

为啥我们需要在 ReactJS 中使用 bind() 来访问 this.props 或 this.state? [复制]