根据serverSocket = new ServerSocket(portNumber)
的理解,我们创建了一个可能“监听”指示端口的对象。通过clientSocket = serverSocket.accept()
,我们强制服务器套接字“监听”其端口,并从任何尝试通过与服务器关联的端口连接到服务器的客户端“接受”连接。当我说“客户端尝试连接到服务器”时,我的意思是客户端程序执行“nameSocket = new Socket(serverIP,serverPort)”。
如果客户端尝试连接到服务器,则服务器“接受”此客户端(即创建与此客户端关联的“客户端套接字”)。
如果新客户端尝试连接到服务器,则服务器会创建另一个客户端套接字(与新客户端关联)。但是服务器如何知道它是一个“新”客户端还是已经有套接字的“旧”客户端?或者,换句话说,如何识别客户?通过他们的IP?通过他们的IP和端口?通过一些“签名”?
如果“旧”客户端再次尝试使用Socket(serverIP,serverIP)会发生什么?服务器是否会创建与此客户端关联的第二个套接字?
答案 0 :(得分:22)
服务器侦听地址和端口。例如,您的服务器的IP地址是10.0.0.1,它正在侦听端口8000。
您的客户端IP地址是10.0.0.2,客户端“连接”到10.0.0.1端口8000的服务器。在TCP连接中,您将提供要连接的服务器的端口。您的客户端实际上会获得自己的端口号,但您无法控制它,并且每个连接都会有所不同。客户端选择要连接的服务器端口,而不是它所连接的客户端端口。
例如,在第一个连接上,您的客户端可能会获得客户端端口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进入。
答案 1 :(得分:5)
每个TCP连接都具有四元组(src端口,src地址,目标端口,目标地址)的标识符。
每当您的服务器接受新客户端时,都会创建一个新的Socket
,并且它与目前为止创建的每个其他套接字无关。客户的识别不会以某种方式处理。
您不必将套接字视为与“客户端”关联,它们与ip和端口关联,但这两者之间没有直接关联。
如果同一个客户端试图通过创建一个新的套接字来打开另一个套接字,那么你将拥有两个不相关的套接字(因为端口肯定会有所不同)。这是因为客户端无法使用相同的端口打开新连接,因此四元组将不同,相同的客户端IP,相同的服务器IP,相同的服务器端口但不同的客户端端口。
编辑您的问题:
顺便说一句,所有这些情况都在 TCP RFC here中清楚解释。
答案 2 :(得分:0)
我认为这里的问题是为什么你关心客户是新的还是旧的。什么是新旧?
例如,Web浏览器可以连接到Web服务器以请求网页。这将创建一个连接,因此serverSocket.accept()
将返回一个新的Socket
。然后,Web浏览器关闭连接。
几分钟后,最后使用点击网页中的链接,浏览器向服务器请求新页面。这将创建一个连接,因此serverSocket.accept()
将返回一个新的Socket
。
现在,Web服务器并不关心这是新客户端还是旧客户端。它只需要服务器请求的页面。如果服务器执行关心“客户端”是否已经过去请求过页面,那么它应该使用套接字上使用的协议中的某些信息来执行此操作。查看http://en.wikipedia.org/wiki/OSI_model
在这种情况下,传输级别上的ServerSocket
和Socket
确认。问题“这个客户端是否已经在服务器上请求了一个页面”应该通过会话甚至应用层的信息来回答。
在Web浏览器/服务器示例中,http协议(应用程序)协议在请求的参数中保存有关此浏览器的用户的信息(浏览器在每次请求时传输cookie信息)。然后,如果浏览器之前连接并最终维护该浏览器的服务器端会话,则http服务器可以设置/读取cookie信息。
回到你的问题:为什么你关心它是新老客户?
答案 3 :(得分:0)
套接字由以下标识:
(本地IP,本地端口,远程IP, 远程端口,IP协议(UDP / TCP / SCTP /等)
这是操作系统用来将数据包/数据映射到程序的正确句柄/文件描述符的信息。对于某些类型的套接字(例如,未连接的UDP套接字),远程端口/远程IP可能是通配符。
答案 4 :(得分:-1)
根据定义,这不是Java相关的问题,而是关于网络的一般问题,因为Sockets和SeverSockets适用于任何支持网络的编程语言。
Socket被绑定到本地端口。客户端将打开与服务器的连接(通过操作系统/ drivers / adapters / hardware / line /.../ line / hardware / adapters / drivers / Server OS)。当您连接到Internet时,此“连接”由称为IP(Internet协议)的协议完成。当您使用“套接字”时,它将使用另一个协议,即TCP / IP协议。
Internet协议将通过两个方面识别网络上的节点:IP地址和端口。 TCP / IP协议将使用IP发送消息,并确保正确接收消息。
现在;回答你的问题:一切都取决于!这取决于您的驱动程序,适配器,硬件,线路。当您连接到本地主机时,您将不会比适配器更进一步。硬件不是必需的,因为实际上没有数据通过线路发送。 (尽管在拥有适配器之前通常需要硬件。)
根据定义,Internet协议将连接定义为一对节点(因此有四件事:两个IP地址和两个端口)。此外,Internet协议定义一个节点一次只能使用一个端口来启动与另一个节点的连接(注意:这仅适用于客户端,而不适用于服务器)。
回答你的第二个问题:如果有两个套接字:“新”和“旧”。由于通过因特网协议,连接是一对节点,并且节点一次只能使用一个端口进行连接,因此“新”和“旧”的端口必须不同。因为这是不同的,“新”客户端可以与“旧”客户端区分开来,因为端口号不同。