2010-02-26 21 views
24

Cách phổ biến trong Java là xác thực và chuyển đổi một chuỗi của biểu mẫu host:port thành một phiên bản InetSocketAddress là gì?Java: Cách thông thường để xác thực và chuyển đổi "host: port" thành InetSocketAddress?

Nó sẽ được tốt đẹp nếu tiêu chuẩn sau đây được đáp ứng:

  • Không tra cứu địa chỉ;

  • Làm việc cho tên máy chủ IPv4, IPv6 và "chuỗi";
    (Đối với IPv4 nó ip:port, cho IPv6 nó [ip]:port, phải không? Có một số RFC trong đó xác định tất cả các chương trình?)

  • Ưu tiên mà không cần phân tích các chuỗi bằng tay.
    (Tôi đang suy nghĩ về tất cả những trường hợp đặc biệt, khi ai đó nghĩ rằng anh ấy biết tất cả các hình thức hợp lệ của địa chỉ socket, nhưng quên về "rằng trường hợp đặc biệt" dẫn đến kết quả bất ngờ.)

+0

Bạn có muốn chỉ địa chỉ IP không? Hay bạn cũng muốn máy chủ hoạt động? – PSpeed

+0

Máy chủ lưu trữ ** và ** địa chỉ IP, nhưng không có bất kỳ tra cứu nào. Những điều có ý nghĩa không chỉ trong một "ngữ cảnh trực tuyến". '1.1.1.1: 123' là địa chỉ ổ cắm internet hợp lệ, vì vậy là' my.host.com: 80', vì vậy là '[:: 1]: 456'. –

+0

máy chủ phân giải thành địa chỉ IP. – AFK

Trả lời

39

Bản thân tôi đề xuất một giải pháp có thể giải quyết khác.

Chuyển đổi chuỗi thành URI (điều này sẽ xác thực tự động) và sau đó truy vấn các thành phần cổng và máy chủ của URI.

Đáng buồn thay, một URI có thành phần máy chủ PHẢI có một lược đồ. Đây là lý do tại sao giải pháp này là "không hoàn hảo".

String string = ... // some string which has to be validated 
String host; 
int port; 

try { 
    // WORKAROUND: add any scheme to make the resulting URI valid. 
    URI uri = new URI("my://" + string); // may throw URISyntaxException 
    host = uri.getHost(); 
    port = uri.getPort(); 

    if (uri.getHost() == null || uri.getPort() == -1) { 
    throw new URISyntaxException(uri.toString(), 
     "URI must have host and port parts"); 
    } 

    // here, additional checks can be performed, such as 
    // presence of path, query, fragment, ... 

} catch (URISyntaxException ex) { 
    // validation failed 
} 

// validation succeeded 

Giải pháp này không cần chuỗi tùy chỉnh phân tích, làm việc với IPv4 (1.1.1.1:123), IPv6 ([::0]:123) và tên host (my.host.com:123).

Vô tình, giải pháp này rất phù hợp với kịch bản của tôi. Tôi sẽ sử dụng lược đồ URI.

+2

Lưu ý rằng nó cũng hoạt động với một vài thứ khác, ví dụ: "my: // foo : bar: baz/"hoặc" my: //[email protected]: 8000/"và cứ thế ... có thể hoặc không có vấn đề gì trong trường hợp của bạn nhưng không thực sự thỏa mãn mong muốn của câu hỏi ban đầu để tránh những thứ "dẫn đến kết quả không mong muốn". :) – PSpeed

+0

Cảm ơn, tôi biết điều đó;) Đã thêm nhận xét vào mã. –

+0

Tính năng này không hoạt động đúng với cổng địa chỉ IPv6. 'Chuỗi máy chủ =" fc00 :: 142: 10 "; \t \t System.out.println (new URI ("my: //" + host) .getHost()); 'Mã này sẽ in ra. – Dikla

2
new InetSocketAddress(
    addressString.substring(0, addressString.lastIndexOf(":")), 
    Integer.parseInt(addressString.substring(addressString.lastIndexOf(":")+1, addressString.length)); 

? Có lẽ tôi đã mắc sai lầm ngớ ngẩn chút nào đó. và tôi giả sử bạn chỉ muốn một đối tượng InetSocketAddress mới ra khỏi String trong định dạng đó. host: port

+4

điều này sẽ không thành công cho IPv6, vì nó giống như '[2001: db8: 85a3 :: 8a2e: 370: 7334]: 80' –

+0

Có lẽ câu hỏi của tôi là sai. Địa chỉ IP có phải là máy chủ lưu trữ không? Tôi không biết. –

+0

bạn đúng là điều này sẽ không thành công cho IPv6. Địa chỉ của máy chủ cũng là Địa chỉ IP. Tôi đoán bạn sẽ chỉ cần đặt trong một tuyên bố nếu trước này và tạo ra một InetSocket dựa trên việc có hay không địa chỉ IP là v6 hoặc v4 – AFK

7

Một regex sẽ làm được điều này khá gọn gàng:

Pattern p = Pattern.compile("^\\s*(.*?):(\\d+)\\s*$"); 
Matcher m = p.matcher("127.0.0.1:8080"); 
if (m.matches()) { 
    String host = m.group(1); 
    int port = Integer.parseInt(m.group(2)); 
} 

Bạn có thể này bằng nhiều cách như làm cho cổng tự chọn hoặc thực hiện một số xác nhận trên máy chủ.

+0

Lưu ý, '^' và '$' là không cần thiết trong trường hợp này vì các kết quả phù hợp() phải khớp với toàn bộ chuỗi. – PSpeed

+0

Mẫu đó quá dễ chấp nhận, ngay cả khi không gian màu trắng phía trước và sau được đổ. Phần cổng, ví dụ, phải nằm trong phạm vi từ 0 đến 65535, và số không có thể chỉ dẫn trong trường hợp 0. Các mô hình cho phần chỉ là một phần cảng là abomination này: '" ((0) | ([1-9] \\ d {0,2}) | ([1-5] \\ d {3}) | ([ 6-9] \\ d {3}) | ([1-5] \\ d {4}) | (6 [0-4] \\ d {3}) | (65 [0-4] \\ d (2)) | (655 [0-2] \\ d) | (6553 [0-5])) "' – Urhixidur

5

Một người khác đã đưa ra câu trả lời chính xác, đó là những gì tôi đã làm để thực hiện khi ban đầu đặt câu hỏi về máy chủ. Tôi vẫn sẽ làm vì nó là một ví dụ về một regex đó là nâng cao hơn một chút và có thể giúp xác định loại địa chỉ bạn đang xử lý.

String ipPattern = "(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}):(\\d+)"; 
String ipV6Pattern = "\\[([a-zA-Z0-9:]+)\\]:(\\d+)"; 
String hostPattern = "([\\w\\.\\-]+):(\\d+)"; // note will allow _ in host name 
Pattern p = Pattern.compile(ipPattern + "|" + ipV6Pattern + "|" + hostPattern); 
Matcher m = p.matcher(someString); 
if(m.matches()) { 
    if(m.group(1) != null) { 
     // group(1) IP address, group(2) is port 
    } else if(m.group(3) != null) { 
     // group(3) is IPv6 address, group(4) is port    
    } else if(m.group(5) != null) { 
     // group(5) is hostname, group(6) is port 
    } else { 
     // Not a valid address   
    } 
} 

Sửa đổi để cổng là tùy chọn khá thẳng về phía trước. Quấn dấu ": (\ d +)" thành "(? :: (\ d +))?" và sau đó kiểm tra null cho nhóm (2), v.v.

Chỉnh sửa: Tôi sẽ lưu ý rằng không có cách "phổ biến" mà tôi biết nhưng ở trên là cách tôi làm nếu tôi có đến.

Cũng lưu ý: trường hợp IPv4 có thể bị xóa nếu máy chủ lưu trữ và trường hợp IPv4 thực sự sẽ được xử lý như nhau. Tôi tách chúng ra bởi vì đôi khi bạn có thể tránh một máy chủ lưu trữ cuối cùng nhìn lên nếu bạn biết bạn có địa chỉ IP.

5

Không trả lời chính xác câu hỏi, nhưng câu trả lời này vẫn có thể hữu ích cho những người khác như tôi chỉ muốn phân tích máy chủ và cổng, nhưng không nhất thiết phải là đầy đủ InetAddress. Ổi có lớp HostAndPort với phương pháp parseString.

+1

Hãy cẩn thận với 'HostAndPort' của ổi. Nó sẽ không thực hiện xác nhận nghiêm ngặt trên tên máy chủ. Vui lòng kiểm tra tài liệu hoặc mã nguồn của lớp học. – stanleyxu2005

+0

Tôi cũng nhận thấy rằng HostAndPort là rất hữu ích, nhưng tôi thấy mình gọi InetAddresses.forString (hostIp) chỉ để xác nhận máy chủ. Làm cho không có ý nghĩa rằng HostAndPort xác nhận cổng là ok nhưng không phải là máy chủ! – titania424

Các vấn đề liên quan