Hai ứng dụng có thể nghe cùng một cổng không?


283

Hai ứng dụng trên cùng một máy có thể liên kết với cùng một cổng và địa chỉ IP không? Tiến thêm một bước nữa, một ứng dụng có thể lắng nghe các yêu cầu đến từ một IP nhất định và một ứng dụng khác đến một IP từ xa khác không? Tôi biết tôi có thể có một ứng dụng bắt đầu hai luồng (hoặc nhánh) để có hành vi tương tự, nhưng hai ứng dụng không có gì chung có thể làm giống nhau không?


2
Để có câu trả lời chi tiết tốt về việc sử dụng lại địa chỉ / cổng có nhiều ổ cắm: stackoverflow.com/questions/14388706/iêu
Bjarke Freund-Hansen

Câu trả lời:


248

Câu trả lời khác nhau tùy thuộc vào hệ điều hành nào đang được xem xét. Nói chung mặc dù:

Đối với TCP, không. Bạn chỉ có thể có một ứng dụng nghe trên cùng một cổng tại một thời điểm. Bây giờ nếu bạn có 2 card mạng, bạn có thể có một ứng dụng nghe trên IP đầu tiên và thứ hai trên IP thứ hai sử dụng cùng một số cổng.

Đối với UDP (Multicasts), nhiều ứng dụng có thể đăng ký vào cùng một cổng.

Chỉnh sửa: Kể từ Linux Kernel 3.9 trở lên, hỗ trợ cho nhiều ứng dụng nghe cùng một cổng đã được thêm bằng SO_REUSEPORTtùy chọn. Thêm thông tin có sẵn tại bài viết lwn.net này.


22
"một ứng dụng lắng nghe trên một cổng" đó là lý do tại sao các cổng tồn tại - để cho phép nhiều ứng dụng chia sẻ mạng mà không có xung đột.
S.Lott

46
Một người nghe trên mỗi cổng cho mỗi địa chỉ IP. Thêm một giao diện mạng khác là một cách để có được địa chỉ IP thứ hai. Nền tảng của bạn có thể hỗ trợ các giao diện ảo, một cách khác để có được hai địa chỉ IP bằng một card mạng vật lý.
John M

7
Mặc dù cho đến bây giờ tôi vẫn có cùng quan điểm, nhưng hóa ra tôi đã có thể liên kết hai quá trình khác nhau với cùng một cổng ip và TCP! Điều này là có thể nếu bạn đặt ServerSocket.setReuseAddress (true) trong Java trước khi liên kết với nó. Hành vi thực sự bất ngờ.
Eugen

7
(1) Ý nghĩa thực sự của câu trả lời của bạn là 'Đối với TCP, vâng, được cung cấp ...' (2) Multicast không phải là điều kiện tiên quyết để chia sẻ cổng UDP, nhưng SO_REUSEADDR thì có.
Hầu tước Lorne

12
Đối với UDP (Multicasts), nhiều ứng dụng có thể đăng ký vào cùng một cổng. Nếu một gói đã đến từ máy khách, ứng dụng nào nhận được nó?
Yang Juven

123

Có (đối với TCP) bạn có thể có hai chương trình nghe trên cùng một ổ cắm, nếu các chương trình được thiết kế để làm như vậy. Khi ổ cắm được tạo bởi chương trình đầu tiên, hãy đảm bảo SO_REUSEADDRtùy chọn được đặt trên ổ cắm trước bạn bind(). Tuy nhiên, đây có thể không phải là những gì bạn muốn. Điều này làm là một kết nối TCP đến sẽ được chuyển đến một trong các chương trình, không phải cả hai, vì vậy nó không trùng lặp kết nối, nó chỉ cho phép hai chương trình phục vụ yêu cầu đến. Ví dụ: các máy chủ web sẽ có nhiều quy trình lắng nghe trên cổng 80 và O / S gửi một kết nối mới đến quy trình sẵn sàng chấp nhận các kết nối mới.

SO_REUSEADDR

Cho phép các ổ cắm khác vào bind()cổng này, trừ khi đã có ổ cắm nghe đang hoạt động gắn kết với cổng. Điều này cho phép bạn khắc phục các thông báo lỗi "Địa chỉ đã sử dụng" khi bạn cố gắng khởi động lại máy chủ của mình sau khi gặp sự cố.


1
TCP + UDP hiện hoạt động (được cung cấp một kernel đủ mới). Xem liên kết tôi thêm vào câu trả lời.
dpb

3
Câu trả lời này không chính xác trừ khi tất cả các ổ cắm bị ràng buộc với các địa chỉ IP riêng biệt không có địa chỉ nào là INADDR_ANY hoặc trừ khi bạn ở trên Windows, nơi kết quả không được xác định.
Hầu tước Lorne

1
Bạn có thể mở rộng về cách dữ liệu đi đến một ứng dụng cụ thể trên cùng một cổng không? Có bất kỳ mối quan tâm bảo mật nào để suy nghĩ khi các ứng dụng sử dụng SO_REUSEADDR hoặc SO_REUSEPORT không?
trusktr

@EJP Bạn cũng có thể xem bình luận trước của tôi?
trusktr

3
SO_REUSEADDRchắc chắn không cho phép bạn có hai ổ cắm TCP ở trạng thái nghe cùng một lúc, ít nhất là trên Unix. Nó có nghĩa là để đi xung quanh TIME_WAIT state: unixguide.net/network/socketfaq/4.5.shtml . Nó có thể hoạt động trên Windows, nhưng bạn không được đảm bảo rằng yêu cầu sẽ đến đúng máy chủ).
Bruno

48

Đúng.

  1. Nhiều ổ cắm TCP nghe, tất cả được liên kết với cùng một cổng, có thể cùng tồn tại, miễn là tất cả chúng đều bị ràng buộc với các địa chỉ IP cục bộ khác nhau. Khách hàng có thể kết nối với bất cứ ai họ cần. Điều này không bao gồm 0.0.0.0( INADDR_ANY).

  2. Nhiều ổ cắm được chấp nhận có thể cùng tồn tại, tất cả được chấp nhận từ cùng một ổ cắm nghe, tất cả đều hiển thị cùng một số cổng cục bộ như ổ cắm nghe.

  3. Nhiều ổ cắm UDP tất cả được liên kết với cùng một cổng đều có thể cùng tồn tại với điều kiện giống như tại (1) hoặc tất cả chúng đều có SO_REUSEADDRtùy chọn được đặt trước khi ràng buộc.

  4. Các cổng TCP và cổng UDP chiếm các không gian tên khác nhau, vì vậy việc sử dụng cổng cho TCP không loại trừ việc sử dụng nó cho UDP và ngược lại.

Tham khảo: Stevens & Wright, TCP / IP Illustrated, Tập II.


bạn có một liên kết trong tay? Cơ hội cùng tồn tại TCP-UDP là câu hỏi của tôi. Cảm ơn trước :)
Sói

1
@Wolf Hãy thử nó. Đó là tất cả bằng chứng bạn thực sự cần. Trích dẫn của tôi là Stevens & Wright: bạn không thể làm tốt hơn thế.
Hầu tước Lorne

1
Cảm ơn đã trả lời, tôi cần đọc thậm chí chăm chú hơn. Bạn đã viết rằng UDP và TCP có thể cùng tồn tại .
Sói

47

Về nguyên tắc, không.

Nó không được viết bằng đá; nhưng đó là cách tất cả các API được viết: ứng dụng mở một cổng, xử lý nó và HĐH sẽ thông báo cho nó (thông qua xử lý đó) khi có kết nối máy khách (hoặc gói trong trường hợp UDP).

Nếu HĐH cho phép hai ứng dụng mở cùng một cổng, làm thế nào để biết ứng dụng nào sẽ thông báo?

Nhưng ... có nhiều cách xung quanh nó:

  1. Như Jed đã lưu ý , bạn có thể viết một quy trình 'chính chủ', đây sẽ là quy trình duy nhất thực sự lắng nghe trên cổng và thông báo cho những người khác, sử dụng bất kỳ logic nào mà nó muốn tách các yêu cầu của khách hàng.
    • Trên Linux và BSD (ít nhất), bạn có thể thiết lập quy tắc 'ánh xạ lại' để chuyển hướng các gói từ cổng 'hiển thị' sang các gói khác nhau (nơi các ứng dụng đang lắng nghe), theo bất kỳ tiêu chí nào liên quan đến mạng (có thể là mạng gốc hoặc một số các hình thức cân bằng tải đơn giản).

37
iptables -m statistic --mode random --probability 0.5là niềm vui
Jed Smith

1
Điều gì chính xác biểu thị "Mở một cổng"? Tôi hiểu câu nhưng bạn có biết chính xác hệ thống làm gì khi mở một cổng và xử lý nó không? Tôi biết rằng khi bạn muốn mở một cổng bằng TCP, bạn sẽ nhận được một luồng và luồng đó là kết nối của bạn với điều khiển từ xa nhưng tôi tìm kiếm trên web và không tìm thấy lời giải thích hay.
Samuel

4
@Samuel: mở một cổng (ở chế độ máy chủ) có nghĩa là nhận được một bộ mô tả tệp và khi hệ thống nhận được gói SYN đến số cổng đó, sẽ phản hồi với SYN + ACK và tạo một sự kiện trên bộ mô tả tệp được liên kết. ứng dụng đáp ứng sự kiện đó bằng một cuộc gọi accept (), tạo ra một bộ mô tả tệp mới được liên kết với luồng cụ thể, để cho bộ mô tả máy chủ ban đầu tự do nhận các kết nối mới từ các máy khách
Javier

7
Câu trả lời này không thể được coi là chính xác. Nó hoàn toàn bỏ qua sự tồn tại của cả SO_REUSEADDR và ​​SO_REUSEPORT.
Hầu tước Lorne

@Javier Không, không. Việc mở một cổng từ quan điểm của ứng dụng máy chủ xảy ra khi bạn liên kết ổ cắm nghe, hay đúng hơn là liên kết ổ cắm mà bạn sắp listen()bật. Có lẽ nhiều câu hỏi là về việc mở nó trong tường lửa. Quá nhiều lỗi ở đây, và tất cả không được sửa chữa trong 7 năm. Trả lời cũng bỏ qua trường hợp ràng buộc với địa chỉ cục bộ khác nhau với cùng một số cổng. Trên thực tế nó hoàn toàn không chính xác.
Hầu tước Lorne

27

Có Chắc chắn . Theo như tôi nhớ Từ phiên bản kernel 3.9 (Không chắc chắn về phiên bản) trở đi, hỗ trợ cho SO_REUSEPORTđã được giới thiệu. SO_RESUEPORTcho phép liên kết với cùng một cổng và địa chỉ chính xác, miễn là máy chủ đầu tiên đặt tùy chọn này trước khi ràng buộc ổ cắm của nó.

Nó hoạt động cho cả TCPUDP . Tham khảo liên kết để biết thêm chi tiết: SO_REUSEPORT

Lưu ý : Câu trả lời được chấp nhận không còn đúng theo quan điểm của tôi.


2
Hoàn toàn đúng. Nếu điều đó không đúng, làm thế nào Wireshark có thể hoạt động?
Staszek

5
@Staszek Wireshark không nghe cổng. Nó hoạt động ở cấp độ gói.
Hầu tước Lorne

Ồ, điều đó sẽ có ý nghĩa. Dù sao, nghe hai cổng bằng 2 ứng dụng là điều chắc chắn có thể.
Staszek

18

Không. Chỉ có một ứng dụng có thể liên kết với một cổng tại một thời điểm và hành vi nếu liên kết bị ép buộc là không xác định.

Với các ổ cắm phát đa hướng - nghe có vẻ không giống với những gì bạn muốn - nhiều ứng dụng có thể liên kết với một cổng miễn là SO_REUSEADDR được đặt trong mỗi tùy chọn của ổ cắm.

Bạn có thể thực hiện điều này bằng cách viết một quy trình "chính", chấp nhận và xử lý tất cả các kết nối, sau đó chuyển chúng cho hai ứng dụng của bạn, những người cần nghe trên cùng một cổng. Đây là cách tiếp cận mà các máy chủ Web và như vậy thực hiện, vì nhiều quy trình cần phải nghe 80.

Ngoài ra, chúng tôi đang đi vào chi tiết cụ thể - bạn đã gắn thẻ cả TCP và UDP, đó là gì? Ngoài ra, nền tảng gì?


cả hai đều quan tâm đến tôi. Nền tảng là các cửa sổ, nhưng nếu câu trả lời là khác nhau đối với Linux, thì thật tuyệt khi biết
nadiv

8
Không có những thứ như ổ cắm đa hướng. Có ổ cắm UDP. Multicast không phải là điều kiện tiên quyết cho SO_REUSEADDR.
Hầu tước Lorne

3

Bạn có thể có một ứng dụng nghe trên một cổng cho một giao diện mạng. Do đó, bạn có thể có:

  1. httpd nghe trên giao diện có thể truy cập từ xa, vd 192.168.1.1:80
  2. một daemon khác lắng nghe 127.0.0.1:80

Trường hợp sử dụng mẫu có thể được sử dụng httpdnhư một bộ cân bằng tải hoặc proxy.


3

Một cách khác là sử dụng một chương trình nghe trong một cổng để phân tích loại lưu lượng truy cập (ssh, https, v.v.) nó chuyển hướng nội bộ sang một cổng khác mà dịch vụ "thực" đang nghe.

Ví dụ: đối với Linux, sslh: https://github.com/yrutschle/sslh


Có một chương trình như vậy trên windows? Tôi cần phải có cả máy chủ IIS cục bộ và nhà môi giới ActiveMQ lắng nghe trên cổng 443
Harvey Lin

3

Khi bạn tạo kết nối TCP, bạn yêu cầu kết nối với một địa chỉ TCP cụ thể, là sự kết hợp của địa chỉ IP (v4 hoặc v6, tùy thuộc vào giao thức bạn đang sử dụng) và một cổng.

Khi một máy chủ lắng nghe các kết nối, nó có thể thông báo cho kernel rằng nó muốn nghe một địa chỉ IP và cổng cụ thể, tức là một địa chỉ TCP hoặc trên cùng một cổng trên mỗi địa chỉ IP của máy chủ (thường được chỉ định bằng địa chỉ IP 0.0.0.0), được hiệu quả lắng nghe trên rất nhiều "địa chỉ TCP" khác nhau (ví dụ như, 192.168.1.10:8000, 127.0.0.1:8000, vv)

Không, bạn không thể có hai ứng dụng nghe trên cùng một "địa chỉ TCP", vì khi có tin nhắn đến, nhân sẽ biết ứng dụng nào sẽ gửi tin nhắn đến ứng dụng nào?

Tuy nhiên, trong hầu hết các hệ điều hành, bạn có thể thiết lập một số địa chỉ IP trên một giao diện (ví dụ: nếu bạn có 192.168.1.10trên một giao diện, bạn cũng có thể thiết lập 192.168.1.11, nếu không có ai khác trên mạng đang sử dụng nó) và trong những trường hợp đó bạn có thể có các ứng dụng riêng biệt nghe trên cổng 8000trên mỗi hai địa chỉ IP đó.


2

Nếu ít nhất một trong số các IP từ xa đã được biết đến, tĩnh và dành riêng để chỉ nói chuyện với một trong các ứng dụng của bạn, bạn có thể sử dụng quy tắc iptables (bảng nat, chuỗi PREROUTING) để chuyển hướng lưu lượng truy cập từ địa chỉ này sang cổng cục bộ "chia sẻ" bất kỳ cổng nào khác, nơi ứng dụng thích hợp thực sự lắng nghe.


1

Có và không. Chỉ có một ứng dụng có thể chủ động lắng nghe trên một cổng. Nhưng ứng dụng đó có thể để lại kết nối của nó với một quá trình khác. Vì vậy, bạn có thể có nhiều quy trình làm việc trên cùng một cổng.


@trusktr, tôi nghĩ anh ấy có ý này
warvariuc


0

Nếu theo ứng dụng, bạn có nghĩa là nhiều quá trình thì có nhưng nói chung là KHÔNG. Ví dụ: máy chủ Apache chạy nhiều quy trình trên cùng một cổng (thường là 80). Nó được thực hiện bằng cách chỉ định một trong các quy trình để thực sự liên kết với cổng và sau đó sử dụng quy trình đó để thực hiện chuyển giao cho các quy trình khác nhau đang chấp nhận kết nối.


0

Bạn có thể làm cho hai ứng dụng nghe cho cùng một cổng trên cùng một giao diện mạng.

Chỉ có thể có một ổ cắm nghe cho giao diện mạng và cổng được chỉ định, nhưng ổ cắm đó có thể được chia sẻ giữa một số ứng dụng.

Nếu bạn có một ổ cắm nghe trong một quy trình ứng dụng và quá trình forkđó, ổ cắm đó sẽ được kế thừa, vì vậy về mặt kỹ thuật sẽ có hai quy trình nghe cùng một cổng.


0

Tôi đã thử như sau, với socat:

socat TCP-L:8080,fork,reuseaddr -

Và mặc dù tôi chưa thực hiện kết nối với ổ cắm, tôi không thể nghe hai lần trên cùng một cổng, bất chấp reuseaddrtùy chọn.

Tôi nhận được tin nhắn này (mà tôi mong đợi trước đây):

2016/02/23 09:56:49 socat[2667] E bind(5, {AF=2 0.0.0.0:8080}, 16): Address already in use

0

Chỉ để chia sẻ những gì @jnewton đã đề cập. Tôi đã bắt đầu một nginx và một quá trình tomcat nhúng trên máy mac của tôi. Tôi có thể thấy cả quá trình runninng ở 8080.

LT<XXXX>-MAC:~ b0<XXX>$ sudo netstat -anp tcp | grep LISTEN
tcp46      0      0  *.8080                 *.*                    LISTEN     
tcp4       0      0  *.8080                 *.*                    LISTEN   

-2

Câu trả lời ngắn:

Đi theo câu trả lời ở đây . Bạn có thể có hai ứng dụng nghe trên cùng một địa chỉ IP và số cổng, do đó, một trong hai cổng là cổng UDP, trong khi ứng dụng khác là cổng TCP.

Giải trình:

Khái niệm cổng có liên quan trên lớp vận chuyển của ngăn xếp TCP / IP, do đó, miễn là bạn đang sử dụng các giao thức lớp vận chuyển khác nhau của ngăn xếp, bạn có thể có nhiều quá trình nghe trên cùng một <ip-address>:<port> kết hợp.

Một nghi ngờ mà mọi người có là nếu hai ứng dụng đang chạy trên cùng một <ip-address>:<port>kết hợp, thì máy khách chạy trên máy từ xa sẽ phân biệt giữa hai ứng dụng như thế nào? Nếu bạn nhìn vào tiêu đề gói lớp IP ( https://en.wikipedia.org/wiki/IPv4#Header ), bạn sẽ thấy các bit 72 đến 79 được sử dụng để xác định giao thức, đây là cách phân biệt có thể được thực hiện.

Tuy nhiên, nếu bạn muốn có hai ứng dụng trên cùng một <ip-address>:<port>kết hợp TCP , thì câu trả lời là không (Một bài tập thú vị sẽ là khởi chạy hai VM, cung cấp cho chúng cùng một địa chỉ IP, nhưng các địa chỉ MAC khác nhau và xem điều gì sẽ xảy ra - đôi khi bạn sẽ nhận thấy rằng VM1 sẽ nhận được các gói và lần khác VM2 sẽ nhận được các gói - tùy thuộc vào việc làm mới bộ đệm ARP).

Tôi cảm thấy rằng bằng cách làm cho hai ứng dụng chạy trên cùng một <op-address>:<port> bạn muốn đạt được một số loại cân bằng tải. Để làm điều này, bạn có thể chạy các ứng dụng trên các cổng khác nhau và viết quy tắc bảng IP để phân chia lưu lượng giữa chúng.

Cũng xem câu trả lời của @ user6169806.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.