时间:2010-07-25 14:57:37

标签: http tcp connection client-server port

5 个答案:

答案 0 :(得分:425)

答案 1 :(得分:333)

重要:

我很遗憾地说“Borealid”的回复是不精确的,有些不正确 - 首先,回答这个问题与有状态或无状态无关,最重要的是,套接字的元组定义是不正确的。

首先请记住以下两条规则:

  1. 套接字的主键:套接字由{SRC-IP, SRC-PORT, DEST-IP, DEST-PORT, PROTOCOL}而不是{SRC-IP, SRC-PORT, DEST-IP, DEST-PORT}标识 - 协议是套接字定义的重要部分。

  2. OS Process&套接字映射:一个进程可以与(可以打开/可以监听)多个套接字关联,这对许多读者来说可能是显而易见的。

  3. 示例1 :连接到同一服务器端口的两个客户端意味着:socket1 {SRC-A, 100, DEST-X,80, TCP}socket2{SRC-B, 100, DEST-X,80, TCP}。这意味着主机A连接到服务器X的端口80,而另一个主机B也连接到同一服务器X到同一端口80.现在,服务器如何处理这两个套接字取决于服务器是单线程还是多线程(我会稍后解释一下)。重要的是一台服务器可以同时收听多个套接字。

    回答帖子的原始问题:

    无论有状态还是无状态协议,两个客户端都可以连接到同一个服务器端口,因为对于每个客户端,我们可以分配不同的套接字(因为客户端IP肯定会有所不同)。同一客户端也可以有两个连接到同一服务器端口的套接字 - 因为这些套接字的区别在于SRC-PORT。公平地说,“Borealid”基本上提到了相同的正确答案,但是对无状态/完全的提及有点不必要/令人困惑。

    回答关于服务器如何知道要回答哪个套接字的问题的第二部分。首先要了解,对于正在侦听同一端口的单个服务器进程,可能有多个套接字(可能来自同一客户端或来自不同客户端)。现在,只要服务器知道哪个请求与哪个套接字相关联,它就可以始终使用相同的套接字响应适当的客户端。因此,服务器永远不需要在其自己的节点中打开另一个端口,而不是客户端最初尝试绑定连接的原始端口。如果任何服务器在绑定套接字后分配不同的服务器端口,那么在我看来服务器正在浪费其资源,它必须要求客户端 bind 再次连接到分配的新端口。

    完整性更多:

    示例2:这是一个非常有趣的问题,服务器的两个不同进程可以监听同一个端口。如果您不将协议视为参数定义套接字之一,则答案为否。主动这是因为我们可以说,在这种情况下,尝试连接到服务器端口的单个客户端将没有任何机制来提及客户端打算进行的两个侦听过程中的哪一个。这与规则(2)所声称的主题相同。然而,这是错误的答案,因为'protocol'也是套接字定义的一部分。因此,只有在使用不同协议时,同一节点中的两个进程才能侦听同一端口。例如,两个不相关的客户端(比如一个使用TCP而另一个使用UDP)可以绑定连接并与同一服务器节点和同一端口进行通信,但它们必须由两个不同的服务器进程提供服务。

    服务器类型 - 单一&多个:

    当服务器的进程侦听意味着多个套接字的端口时,可以同时连接并与同一服务器进程通信。如果服务器只使用一个子进程来为所有套接字提供服务,则服务器称为单进程/线程,如果服务器使用许多子进程通过一个子进程为每个套接字提供服务,则服务器被称为多个进程/线程服务器。请注意,无论服务器的类型如何,服务器都可以/应该始终使用相同的初始套接字来响应(不需要分配另一个服务器端口)。

    如果可以的话,建议Books和其他两卷。

    关于父/子过程的说明(回应'Ioan Alexandru Cucu'的查询/评论)

    无论我在哪里提到与A和B两个流程相关的任何概念,都要考虑它们与父子关系无关。操作系统(尤其是UNIX)允许子进程从父进程继承所有文件描述符(FD)。因此,进程A监听的所有套接字(在UNIX中都是OS的一部分也是FD的一部分)可以被更多进程A1,A2,...监听,只要它们通过父子关系与A相关联。独立进程B(即与A没有父子关系)不能听同一个套接字。此外,还要注意,禁止两个独立进程侦听相同套接字的规则存在于操作系统(或其网络库)中,并且到目前为止大多数操作系统都遵守该规则。但是,可以创建自己的操作系统,这很可能违反这些限制。

答案 2 :(得分:160)

端口上的TCP / HTTP侦听:许多用户如何共享同一端口

那么,当服务器侦听TCP端口上的传入连接时会发生什么?例如,假设您在端口80上有一个Web服务器。假设您的计算机的公共IP地址为24.14.181.229,并且尝试连接到您的人的IP地址为10.1.2.3。此人可以通过打开到24.14.181.229:80的TCP套接字连接到您。很简单。

直觉(和错误地),大多数人认为它看起来像这样:

    Local Computer    | Remote Computer
    --------------------------------
    <local_ip>:80     | <foreign_ip>:80

    ^^ not actually what happens, but this is the conceptual model a lot of people have in mind.

这很直观,因为从客户端的角度来看,他有一个IP地址,并连接到IP:PORT的服务器。由于客户端连接到端口80,那么他的端口也必须是80?这是一个明智的想法,但实际上不会发生什么。如果这是正确的,我们只能为每个外部IP地址服务一个用户。一旦远程计算机连接,他就会将端口80占用端口80连接,而其他任何人都无法连接。

必须理解三件事:

1。)在服务器上,进程在端口上监听。一旦获得连接,它就会将其交给另一个线程。通信永远不会占用监听端口。

2.)操作系统通过以下5元组唯一标识连接:(本地IP,本地端口,远程IP,远程端口,协议)。如果元组中的任何元素不同,那么这是一个完全独立的连接。

3.)当客户端连接到服务器时,它会选择随机,未使用的高阶源端口。这样,单个客户端可以为同一目标端口提供最多约64k的服务器连接。

因此,这实际上是客户端连接到服务器时创建的内容:

    Local Computer   | Remote Computer           | Role
    -----------------------------------------------------------
    0.0.0.0:80       | <none>                    | LISTENING
    127.0.0.1:80     | 10.1.2.3:<random_port>    | ESTABLISHED

看看实际发生了什么

首先,让我们使用netstat来查看这台计算机上发生了什么。我们将使用端口500而不是80(因为端口80上发生了大量的东西,因为它是一个公共端口,但在功能上它并没有什么区别)。

    netstat -atnp | grep -i ":500 "

正如预期的那样,输出是空白的。现在让我们启动一个Web服务器:

    sudo python3 -m http.server 500

现在,这是再次运行netstat的输出:

    Proto Recv-Q Send-Q Local Address           Foreign Address         State  
    tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      - 

所以现在有一个进程在端口500上主动侦听(状态:LISTEN)。本地地址是0.0.0.0,这是“全部监听”的代码。一个容易犯的错误是侦听地址127.0.0.1,它只接受来自当前计算机的连接。所以这不是连接,这只是意味着请求绑定()到端口IP的进程,并且该进程负责处理到该端口的所有连接。这暗示了每个计算机只能在一个端口上监听一个进程的限制(有多种方法可以使用多路复用来解决这个问题,但这是一个更复杂的主题)。如果Web服务器正在侦听端口80,则它无法与其他Web服务器共享该端口。

现在,让我们将用户连接到我们的机器:

    quicknet -m tcp -t localhost:500 -p Test payload.

这是一个简单的脚本(https://github.com/grokit/dcore/tree/master/apps/quicknet),用于打开TCP套接字,发送有效负载(在本例中为“测试有效负载”),等待几秒钟并断开连接。发生这种情况时再次执行netstat会显示以下内容:

    Proto Recv-Q Send-Q Local Address           Foreign Address         State  
    tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      -
    tcp        0      0 192.168.1.10:500        192.168.1.13:54240      ESTABLISHED -

如果您与其他客户端连接并再次执行netstat,您将看到以下内容:

    Proto Recv-Q Send-Q Local Address           Foreign Address         State  
    tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      -
    tcp        0      0 192.168.1.10:500        192.168.1.13:26813      ESTABLISHED -

...也就是说,客户端使用另一个随机端口进行连接。所以IP地址之间永远不会混淆。

答案 3 :(得分:25)

答案 4 :(得分:4)

多个客户端可以连接到服务器上的同一个端口(例如80),因为在服务器端,创建套接字绑定之后(设置本地IP和端口)在套接字上调用 listen ,告诉操作系统接受传入的连接。

当客户端尝试连接到端口80上的服务器时,将在服务器套接字上调用 accept 调用。这为尝试连接的客户端创建了一个新套接字,同样地,将为使用相同端口80的后续客户端创建新套接字。

斜体字是系统调用。

参考

http://www.scs.stanford.edu/07wi-cs244b/refs/net2.pdf