我对Socket和ServerSocket端口的使用感到困惑。 Oracle's java tutorial about sockets说以下内容:
什么是套接字?
通常,服务器在特定计算机上运行,并且具有绑定到特定端口号的套接字。服务器只是等待,监听套接字以便客户端发出连接请求。 在客户端:客户端知道运行服务器的计算机的主机名以及服务器正在侦听的端口号。要发出连接请求,客户端会尝试与服务器的计算机和端口上的服务器会合。客户端还需要向服务器标识自己,以便绑定到在此连接期间将使用的本地端口号。这通常由系统分配。
如果一切顺利,服务器会接受连接。的一旦 接受,服务器获取绑定到同一本地端口的新套接字 并且还将其远程端点设置为的地址和端口 客户。它需要一个新的套接字,以便它可以继续听取 连接请求的原始套接字,同时满足需要 连接的客户端。
在客户端,如果接受连接,则成功创建套接字,客户端可以使用套接字与服务器通信。 客户端和服务器现在可以通过写入或读取其套接字来进行通信。
我尝试了以下代码进行测试。但它引发了一个例外。
try {
ServerSocket serverSocket = new ServerSocket(8080);
Socket socket = serverSocket.accept();
// This prints 8080
System.out.println("Local port of accepted socket : " + socket.getLocalPort());
// But this throws java.net.BindException: Address already in use: JVM_Bind
Socket myClientSocket = new Socket("www.google.com", 80, null, 8080);
} catch (Exception e) {
e.printStackTrace();
}
我的问题很明显。从serverSocket.accept()
返回的套接字可以使用相同的本地端口(8080
),为什么我创建的套接字无法使用它?
答案 0 :(得分:1)
为了简单起见,侦听TCP套接字已经明确绑定到端口,因此您无法将第二个TCP套接字显式绑定到同一端口(除非两个套接字也明确绑定到不同的IP地址,不包括INADDR_ANY)。
接受的套接字不会通过明确的“绑定”过程。它们自动获取本地IP地址和端口,如果连接它而没有绑定,则出站套接字也是如此。
答案 1 :(得分:-1)
您的服务器和客户端使用相同的本地端口进行通信。当您创建服务器套接字时,您“说”它必须在8080端口上侦听。没关系。任何想要与服务器套接字通信的人都必须使用这样的端口。
但是,正好在下面你创建了一个客户端套接字,使用端口80连接谷歌网站(谷歌正在监听该端口),在最后一个参数中,你说这个套接字必须也使用本地端口8080建立连接。一次只有一个连接可以使用一个端口,这就是为什么你得到java.net.BindException,服务器和客户端连接都使用8080。
我的建议......从套接字客户端构造函数中获取最后两个参数,或者更改本地客户端端口(总是得到一个高数字以避免与其他进程相同的问题):
Socket myClientSocket = new Socket("www.google.com", 80);
或
Socket myClientSocket = new Socket("www.google.com", 80, null, 58080);