任何人都可以告诉我如何在服务器决定接受客户端连接后设置客户端端口号。我希望客户端的端口号应该在50000到60000之间。
答案 0 :(得分:2)
如果您询问如何编码服务器以设置客户端的端口,那么答案是您不能。客户端选择自己的端口,并且在服务器参与时已经在使用它。
如果您询问如何编码客户端以选择与服务器连接的本地端口,则可以查看Socket
的文档。
如果您未指定端口,则操作系统会从其ephemeral port range中提供任意端口号。
如果确实指定了本地端口,例如使用构造函数public Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
,则客户端将尝试绑定到该本地端口。
但是,如果端口不可用,则会失败。我们通常要求操作系统提供短暂端口的原因是,当同一客户端的两个实例或套接字保持TIME_WAIT
状态时,应避免“使用中的地址”失败。
没有API可以让您向操作系统询问给定范围内的短暂端口。
你能做的最好的事情就是要求一个任意的端口,并在一个循环中重试,直到你得到一个在你想要的范围内:
Socket socket;
do {
socket = new Socket();
socket.bind(null); // null means any local address, ephemeral port
} while (! isInRange(socket.getLocalPort());
socket.connect(...);
这种效率低下是显而易见的;在遇到可接受的插座之前,你可以创建并丢弃任意数量的插座。如果你想要的范围是操作系统短暂范围的一大块,那么这是一种合理的方法。
或者,您可以遍历可接受的范围,捕获绑定错误并重试:
Socket socket = new Socket();
for ( int port = MIN_PORT ; port <= MAX_PORT; port++ )
{
try {
s.bind(new InetSocketAddress(port));
break;
} catch (IllegalArgumentException | IOException e) {
// try the next port
}
// deal with not having found a suitable port
}
socket.connect(...);
这有不同的低效率,如果客户经常并发地运行,这将变得特别相关。你经常在范围下端的端口“战斗”。如果你必须使用这种方法,那么至少要开始查看范围内的随机位置是值得修改的。
如果您这样做的动机是绕过防火墙规则,请尽量修复(愚蠢,毫无意义的)防火墙规则。但是,有些客户端使用我所描述的方法,因为有时防火墙管理员不会放弃。
答案 1 :(得分:1)
您需要的构造函数是
public Socket(InetAddress address,
int port,
InetAddress localAddr,
int localPort)
此方法允许您提供特定的源端口。您可以随意选择一个,如果已经采用则重试。