简体   繁体   English

如何在Java中设置客户端端口号?

[英]How to set client port number in java?

Can anyone please tell me how to set a client port numbers once the server decides to accept the connection of the client. 服务器决定接收客户端连接后,谁能告诉我如何设置客户端端口号。 I want the port number of client should be between 50000 to 60000. 我希望客户端的端口号应在50000到60000之间。

If you are asking how to code the server in order to set the client 's port, then the answer is that you can't. 如果您询问如何对服务器进行编码以设置客户端的端口,那么答案是您不能。 The client chooses its own port, and that is already in use by the time the server is involved. 客户端选择自己的端口,并且在涉及服务器时该端口已经在使用中。


If you are asking how to code the client to choose a local port for a connection to the server, then the documentation for Socket is the place to look. 如果您询问如何对客户端进行编码,以选择与服务器连接的本地端口,则可以查看Socket文档。

If you don't specify a port, then the OS gives an arbitrary port number from its ephemeral port range . 如果您未指定端口,则操作系统会根据其临时端口范围提供任意端口号。

If you do specify a local port, for example with the constructor public Socket(InetAddress address, int port, InetAddress localAddr, int localPort) then the client will attempt to bind to that local port. 如果您确实指定了本地端口,例如使用构造函数public Socket(InetAddress address, int port, InetAddress localAddr, int localPort)则客户端将尝试绑定到该本地端口。

However this will fail if the port is not available. 但是,如果端口不可用,这将失败。 The reason we typically ask the OS for an ephemeral port is to avoid "address in use" failures when two instances of the same client, or when a socket remains in TIME_WAIT status. 我们通常要求操作系统提供临时端口的原因是为了避免当同一客户端的两个实例或套接字保持TIME_WAIT状态时出现“使用中的地址”失败。

There is no API that lets you ask the OS for an ephemeral port in a given range. 没有任何API可以让您向OS请求给定范围内的临时端口。

The best you can do is to ask for an arbitrary port, and retry in a loop until you get one that's in your desired range: 最好的办法是请求一个任意端口,然后循环尝试,直到获得所需范围内的端口:

 Socket socket;
 do {
    socket = new Socket();
    socket.bind(null); // null means any local address, ephemeral port
 } while (! isInRange(socket.getLocalPort());
 socket.connect(...);

The inefficiency of this is obvious; 这种做法的效率很低; you could create and discard any number of sockets before stumbling on an acceptable one. 您可以创建和丢弃任意数量的套接字,然后再踩在可接受的套接字上。 It's a reasonable approach if your desired range is a good sized chunk of the OS's ephemeral range. 如果您希望的范围是操作系统临时范围的一个适当大小的部分,那么这是一种合理的方法。

Alternatively you can loop through your acceptable range, catching bind errors and retrying: 或者,您可以遍历可接受的范围,捕获绑定错误并重试:

    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(...);

This has different inefficiencies, which would become especially relevant if the client runs frequently and concurrently. 这有不同的效率低下,如果客户端频繁并发运行,这将变得尤为重要。 You'd constantly be "fighting" over the ports in the lower end of the range. 您将不断地在范围较低端的端口上进行“战斗”。 If you must use this approach, it would be worth amending it to at least start looking at a random position within the range. 如果必须使用此方法,则值得对其进行修改,以至少开始查看范围内的随机位置。


If your motivation to do this is to get around a firewall rule, try hard to get the (stupid, pointless) firewall rule fixed. 如果您这样做的动机是绕过防火墙规则,请尝试解决(愚蠢,毫无意义的)防火墙规则。 However, there are clients in the wild that do use the approach I've described, because sometimes the firewall admin just won't give up. 但是,有些客户端确实使用了我描述的方法,因为有时防火墙管理员不会放弃。

The constructor you need is 您需要的构造函数是

public Socket(InetAddress address,
              int port,
              InetAddress localAddr,
              int localPort)

https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#Socket-java.net.InetAddress-int-java.net.InetAddress-int- https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#Socket-java.net.InetAddress-int-java.net.InetAddress-int-

This method allows you to give a specific source port. 此方法允许您提供特定的源端口。 You can chose one at random and retry if it's already taken. 您可以随机选择一个,然后重试(如果已使用)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM