【问题标题】:How the clients (client sockets) are identified?如何识别客户端(客户端套接字)?
【发布时间】:2011-01-27 05:21:55
【问题描述】:

根据serverSocket = new ServerSocket(portNumber) 的理解,我们创建了一个对象,它可能“监听”指定的端口。通过clientSocket = serverSocket.accept(),我们强制服务器套接字“监听”其端口并“接受”来自任何试图通过与服务器关联的端口连接到服务器的客户端的连接。当我说“客户端尝试连接到服务器”时,我的意思是客户端程序执行“nameSocket = new Socket(serverIP,serverPort)”。

如果客户端试图连接到服务器,服务器“接受”这个客户端(即创建一个与这个客户端关联的“客户端套接字”)。

如果新客户端尝试连接到服务器,服务器会创建另一个客户端套接字(与新客户端关联)。但是服务器如何知道它是“新”客户端还是已经拥有套接字的“旧”客户端?或者,换句话说,如何识别客户?通过他们的IP?通过他们的IP和端口?通过一些“签名”?

如果“旧”客户端再次尝试使用 Socket(serverIP,serverIP) 会发生什么?服务器会创建与该客户端关联的第二个套接字吗?

【问题讨论】:

    标签: networking sockets client-server


    【解决方案1】:

    服务器侦听地址和端口。例如,您的服务器的 IP 地址是 10.0.0.1,它正在监听 8000 端口。

    您的客户端 IP 地址是 10.0.0.2,客户端“连接”到服务器的 10.0.0.1 端口 8000。在 TCP 连接中,您提供了要连接的服务器的端口。您的客户端实际上将获得自己的端口号,但您无法控制它,并且每个连接都会有所不同。客户端选择它想要连接的 server 端口,而不是它要连接的 client 端口。

    例如,在第一次连接时,您的客户端可能会获得客户端端口 12345。它从 10.0.0.2 端口 12345 连接到服务器 10.0.0.1 端口 8000。您的服务器可以看到客户端从哪个端口连接通过在连接端调用 getpeername。

    当客户端第二次连接时,端口号会有所不同,例如端口 12377。服务器可以通过在第二次连接上调用 getpeername 来看到这一点——它将在客户端看到不同的端口号。 (getpeername 还显示客户端的 IP 地址。)

    此外,每次您在服务器上调用 accept 时,您都会获得一个新的套接字。您仍然拥有原始套接字侦听,并且在每次接受时都会获得一个新套接字。在接受的套接字上调用 getpeername 以查看连接来自哪个客户端端口。如果有两个客户端连接到您的服务器,您现在就有了三个套接字——原始监听套接字和两个客户端各自的套接字。

    您可以让多个客户端同时连接到同一个服务器端口 8000。而且,许多客户端可以从同一个客户端端口(例如端口 12345)连接,但不能从同一个 IP 地址连接。来自相同的客户端 IP 地址,例如10.0.0.2,到服务器端口 8000 的每个客户端连接都将来自一个唯一的客户端端口,例如12345、12377等。您可以通过IP地址和端口的组合来区分客户端。

    同一个客户端也可以同时与服务器建立多个连接,例如一个来自客户端端口 12345 的连接,另一个来自 12377 的连接。客户端是指原始 IP 地址,而不是特定的软件对象。您只会看到两个具有相同客户端 IP 地址的活动连接。

    此外,最终随着时间的推移,客户端地址和客户端端口的组合可以重复使用。也就是说,在 10.0.0.2 端口 12345 的第一个客户端断开连接很久之后,您最终可能会看到一个新客户端从 10.0.0.2 端口 12345 进来。

    【讨论】:

    • 最后一段略有错误。新客户端可能会在相同 IP 和端口上的第一个客户端之后(不一定在很长时间之后)进入。对于 TCP,服务器可以通过 SYN/ACK/FIN 数据包(全部由 SOCKETS 层处理)来判断它是新连接的方式。对于 RAW 或 UDP 套接字,由应用程序决定什么是新连接,什么是现有连接。
    • @JasonR.Coombs 您的评论忽略了 TIME_WAIT 状态,这会故意阻止您所描述的内容,并使此答案的最后一段正确。
    【解决方案2】:

    每个 TCP 连接都有四元组作为标识符(src 端口,src 地址,dest 端口,dest 地址)

    每当您的服务器接受一个新客户端时,就会创建一个新的Socket,并且它独立于迄今为止创建的所有其他套接字。客户的识别并没有以某种方式隐式处理..

    您不必将套接字视为与“客户端”相关联,它们与 ip 和端口相关联,但这两者之间没有直接关联。

    如果同一个客户端尝试通过创建一个新套接字来打开另一个套接字,您将拥有两个不相关的套接字(因为端口肯定会不同)。这是因为客户端不能使用相同的端口来打开新的连接,所以四元组将是不同的,相同的客户端 ip,相同的服务器 ip,相同的服务器端口但不同的客户端端口。

    编辑您的问题:

    1. 客户端没有指定端口,因为它是从底层操作系统的空闲端口中随机选择的(如果我没记错的话,应该是 1024)
    2. 无法从使用相同端口的客户端打开连接,操作系统不允许您这样做(实际上您根本没有指定任何端口)并且无论如何它会告诉您该端口已经绑定到套接字,因此不会发生此问题。
    3. 每当服务器收到一个新的连接请求时,它就被认为是新的,因为如果 ip 是同一个端口,肯定会有所不同(在旧数据包重新发送或类似警告的情况下,我认为该请求将被丢弃)李>

    顺便说一下,所有这些情况在 TCP RFC here 中都有明确的解释。

    【讨论】:

    • @Jack,但是客户端如何选择要连接的端口?在我的客户端代码示例中,客户端尝试通过指定服务器地址和服务器端口来连接到服务器。 IE。服务器不要指定它尝试连接到服务器的端口。
    • @Jack,我是否正确理解你,监听特定端口的服务器套接字,只有当客户端从尚未使用的 clientIP-clientPort 调用时才会创建新的客户端套接字以前?
    • @Jack,你写“只要你的服务器接受一个新的客户端,就会创建一个新的 Socket”。但是您如何定义“新”客户?服务器如何知道特定客户端是“新”还是“旧”。如果已经有一个与客户端调用的 IP 端口相关联的套接字,我可以说客户端被视为“旧”客户端吗?
    • 客户端对 HTTP 和 HTTPS 的请求有什么区别?客户端对 HTTPS 服务器的每个请求是否创建不同的套接字?
    • @Roman 服务器应用程序不必知道。它只有插座。不管是新的还是旧的。
    【解决方案3】:

    我认为这里的问题是您为什么要关心客户是新客户还是旧客户。什么是新旧? 例如,网络浏览器可以连接到网络服务器以请求网页。这将创建一个连接,因此serverSocket.accept() 将返回一个新的Socket。然后连接被网络浏览器关闭。

    几分钟后,用户点击网页中的链接,浏览器向服务器请求一个新页面。这将创建一个连接,因此serverSocket.accept() 将返回一个新的Socket

    现在,Web 服务器不关心这是新客户端还是旧客户端。它只需要服务器请求的页面。如果服务器确实关心“客户端”过去是否已经请求过一个页面,它应该使用套接字上使用的协议中的一些信息来这样做。查看http://en.wikipedia.org/wiki/OSI_model 在这种情况下,ServerSocketSocket 在传输层上确认。 “这个客户端是否已经请求了服务器上的页面”这个问题应该通过会话甚至应用层的信息来回答。

    在 Web 浏览器/服务器示例中,http 协议(它是一个应用程序)协议在请求的参数中保存有关此浏览器的信息(浏览器在每个请求中传输 cookie 信息)。然后,http 服务器可以设置/读取 cookie 信息以了解浏览器之前是否连接,并最终为该浏览器维护服务器端会话。

    回到你的问题:你为什么关心它是新客户还是老客户?

    【讨论】:

      【解决方案4】:

      通过以下方式标识套接字:

      (本地IP,本地端口,远程IP, 远程端口,IP协议(UDP/TCP/SCTP/等)

      这就是操作系统用来将数据包/数据映射到程序的正确句柄/文件描述符的信息。对于某些类型的套接字(例如未连接的 UDP 套接字),远程端口/远程 IP 可能是通配符。

      【讨论】:

        【解决方案5】:

        根据定义,这不是 Java 相关的问题,而是一般的网络问题,因为 Socket 和 SeverSockets 适用于任何支持网络的编程语言。

        一个 Socket 被绑定到一个本地端口。客户端将打开与服务器的连接(通过操作系统/驱动程序/适配器/硬件/线路/.../线路/硬件/适配器/驱动程序/服务器操作系统)。当您连接到 Internet 时,这种“连接”是通过称为 IP(Internet 协议)的协议完成的。当您使用“Sockets”时,它将使用另一个协议,即 TCP/IP 协议。

        互联网协议将通过两件事来识别网络上的节点:它们的 IP 地址和它们的端口。 TCP/IP 协议将使用 IP 发送消息,并确保正确接收消息。

        现在;回答你的问题:这一切都取决于!这取决于您的驱动程序、适配器、硬件和线路。当您连接到您的本地主机机器时,您不会比适配器更进一步。硬件不是必需的,因为实际上没有数据通过线路发送。 (虽然您通常需要硬件才能拥有适配器。)

        根据定义,互联网协议将连接定义为一对节点(因此有四件事:两个 IP 地址和两个端口)。此外,互联网协议定义了一个节点一次只能使用一个端口来启动与另一个节点的连接(注意:这仅适用于客户端,不适用于服务器)。

        回答你的第二个问题:如果有两个套接字:“新”和“旧”。由于根据 Internet 协议,连接是一对节点,并且节点一次只能使用一个端口进行连接,因此“新”和“旧”的端口必须不同。并且由于这是不同的,“新”客户端可以与“旧”客户端区分开来,因为端口号不同。

        【讨论】:

        • @Pindatjuh,我是否理解正确。如果客户端从相同的 IP 地址和相同的端口调用套接字,则侦听特定端口的服务器套接字将不会创建新的客户端套接字。
        • 作为连接到服务器的客户端,您无法确定您的端口。只有服务器可以在同一个端口上有多个“传入连接”,但客户端不能在同一个端口上有多个“传出连接”。但是,它可以重用连接,但必须先关闭它。通知服务器关闭连接。
        • 答案大多不正确。 IP 层既不存在连接也不存在端口。它们是 TCP 层的功能。您也可以在 IP 级别或其他级别使用套接字。端口唯一性的讨论也是不正确的:连接的 5 元组必须是唯一的,而不是单个端口号。您的评论也不正确:客户端确实可以定义自己的端口。通常不会这样做,但有可能。没有重复使用连接这样的事情。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-05-06
        • 2021-10-22
        • 1970-01-01
        • 2012-02-19
        • 2011-04-21
        • 1970-01-01
        • 2015-02-08
        相关资源
        最近更新 更多