Hàm socket chấp nhận () hoạt động như thế nào?


126

API socket là tiêu chuẩn thực tế cho truyền thông TCP / IP và UDP / IP (nghĩa là mã mạng như chúng ta biết). Tuy nhiên, một trong những chức năng cốt lõi của nó, accept()là một chút ma thuật.

Để mượn một định nghĩa bán chính thức:

accept () được sử dụng ở phía máy chủ. Nó chấp nhận một nỗ lực đến nhận được để tạo kết nối TCP mới từ máy khách từ xa và tạo một ổ cắm mới được liên kết với cặp địa chỉ ổ cắm của kết nối này.

Nói cách khác, accepttrả về một ổ cắm mới thông qua đó máy chủ có thể giao tiếp với máy khách mới được kết nối. Ổ cắm cũ (trên đóaccept được gọi) vẫn mở, trên cùng một cổng, lắng nghe các kết nối mới.

Làm thế nào để acceptlàm việc? Nó được thực hiện như thế nào? Có rất nhiều nhầm lẫn về chủ đề này. Nhiều người tuyên bố chấp nhận mở một cổng mới và bạn giao tiếp với khách hàng thông qua cổng đó. Nhưng điều này rõ ràng là không đúng, vì không có cổng mới nào được mở. Bạn thực sự có thể giao tiếp qua cùng một cổng với các máy khách khác nhau, nhưng bằng cách nào? Khi một số luồng gọi recvtrên cùng một cổng, làm thế nào để dữ liệu biết đi đâu?

Tôi đoán đó là thứ gì đó dọc theo dòng địa chỉ của khách hàng được liên kết với bộ mô tả ổ cắm và bất cứ khi nào dữ liệu đi qua recvnó được chuyển đến đúng ổ cắm, nhưng tôi không chắc chắn.

Thật tuyệt khi có được một lời giải thích kỹ lưỡng về hoạt động bên trong của cơ chế này.


2
vì vậy đối với mỗi yêu cầu của khách hàng, một kết nối ổ cắm MỚI hoàn toàn ở cuối máy chủ được mở. Máy chủ phải luôn mở ở 80 để lắng nghe các cuộc gọi đến. Nếu nó nhận được một cuộc gọi, thì nó sẽ ngay lập tức tạo ra một socket MỚI với bốn bộ dữ liệu như được đề cập dưới đây, điều này sẽ tạo ra kết nối TCP giữa máy khách và máy chủ. Tôi hiểu có đúng không?
cơn bão não

1
Đây là một câu hỏi rất cơ bản và thời gian gần đây tôi đã được thử nghiệm về điều này trong một cuộc phỏng vấn: stackoverflow.com/questions/24871827/... Nếu bạn có bất kỳ ý kiến về vấn đề này, xin vui lòng gửi
cơn bão não

@brainstorm Chỉ khi bạn hoàn toàn bỏ qua sự tồn tại của HTTP keep-life.
Hầu tước Lorne

Câu trả lời:


140

Sự nhầm lẫn của bạn nằm ở chỗ nghĩ rằng một ổ cắm được xác định bởi IP máy chủ: Cổng máy chủ. Khi trong thực tế, các ổ cắm được xác định duy nhất bởi một bộ thông tin:

Client IP : Client PortServer IP : Server Port

Vì vậy, trong khi IP máy chủ và Cổng máy chủ không đổi trong tất cả các kết nối được chấp nhận, thông tin phía máy khách là thứ cho phép nó theo dõi mọi thứ đang diễn ra ở đâu.

Ví dụ để làm rõ mọi thứ:

Nói rằng chúng tôi có một máy chủ tại 192.168.1.1:80và hai khách hàng, 10.0.0.110.0.0.2.

10.0.0.1mở một kết nối trên cổng cục bộ 1234và kết nối với máy chủ. Bây giờ máy chủ có một ổ cắm được xác định như sau:

10.0.0.1:1234 - 192.168.1.1:80  

Bây giờ 10.0.0.2mở một kết nối trên cổng cục bộ 5678và kết nối với máy chủ. Bây giờ máy chủ có hai ổ cắm được xác định như sau:

10.0.0.1:1234 - 192.168.1.1:80  
10.0.0.2:5678 - 192.168.1.1:80

3
Tôi không biết chi tiết triển khai (có thể thay đổi từ nền tảng này sang nền tảng khác), tôi chỉ biết rằng về mặt khái niệm các ổ cắm được xác định bởi bộ tứ thông tin mà tôi đã mô tả.
17 trên 26

3
Bạn có bất cứ tài liệu tham khảo về điều này?
qeek

3
Câu hỏi ngẫu nhiên: Điều gì xảy ra nếu NAT đang được sử dụng và hai máy khách trên cùng một mạng cố gắng sử dụng cùng một cổng cục bộ khi kết nối với máy chủ? Chẳng hạn, nếu 10.0.0.1 và 10.0.0.2 đều được kết nối với bộ định tuyến có IP bên ngoài là 192.168.0.1, thì máy chủ tại 192.168.1.1 sẽ thấy hai kết nối từ 192.168.0.1. Điều gì xảy ra trong trường hợp đó nếu bởi một số dòng của bộ tạo số ngẫu nhiên cả 10.0.0.1 và 10.0.0.2 chọn cùng một cổng cục bộ?
aroth

4
Hỗ trợ NAT trong bộ định tuyến đảm nhiệm các chi tiết ở đó. Lưu lượng mạng thực sự đi qua hai kết nối - máy khách đến bộ định tuyến và bộ định tuyến đến máy chủ. Bộ định tuyến thực hiện các kết nối đi trên hai cổng khác nhau 192.168.0.1:1234 và 192.168.0.1 giáp678. Lưu lượng đến sau đó được chuyển hướng bởi bộ định tuyến đến đúng máy khách.
17 trên 26 tháng

3
Nếu một ổ cắm được xác định bởi bộ tứ, thông tin bộ tứ của ổ cắm nghe là gì?
Eric Zheng

74

Chỉ cần thêm vào câu trả lời của người dùng "17 trên 26"

Ổ cắm thực sự bao gồm 5 tuple - (ip nguồn, cổng nguồn, ip đích, cổng đích, giao thức). Ở đây giao thức có thể TCP hoặc UDP hoặc bất kỳ giao thức lớp vận chuyển nào. Giao thức này được xác định trong gói từ trường 'giao thức' trong IP datagram.

Do đó, có thể phải có các ứng dụng khác nhau trên máy chủ giao tiếp với cùng một máy khách trên cùng 4 bộ dữ liệu nhưng khác nhau trong trường giao thức. Ví dụ

Apache ở phía máy chủ nói chuyện trên (server1.com:880-client1:1234 trên TCP) và World of Warcraft nói chuyện trên (server1.com:880-client1:1234 trên UDP)

Cả máy khách và máy chủ sẽ xử lý trường này dưới dạng trường giao thức trong gói IP trong cả hai trường hợp là khác nhau ngay cả khi tất cả 4 trường khác đều giống nhau.


13

Điều làm tôi bối rối khi tôi học điều này, đó là các thuật ngữ socketportgợi ý rằng chúng là một thứ gì đó vật lý, trong khi thực tế chúng chỉ là cấu trúc dữ liệu mà hạt nhân sử dụng để trừu tượng hóa các chi tiết của mạng.

Như vậy, các cấu trúc dữ liệu được triển khai để có thể tách rời các kết nối khỏi các máy khách khác nhau. Về cách chúng được triển khai, câu trả lời là một.) Không thành vấn đề, mục đích của API socket chính xác là việc triển khai không quan trọng hoặc b.) Chỉ cần xem xét. Ngoài các sách Stevens được đề xuất cao cung cấp mô tả chi tiết về một triển khai, hãy xem nguồn trong Linux hoặc Solaris hoặc một trong các BSD.


Có, hầu hết các thuật ngữ mạng chỉ là gán tên cho các tập hợp bit nhất định và cho các quyết định được đưa ra dựa trên các giá trị của chúng ("định danh giao thức", "định tuyến", "liên kết", "ổ cắm", v.v.). Tất cả phần cứng của card mạng của bạn được thiết kế để nhận là một luồng bit. Điều gì xảy ra với họ liên quan đến các chương trình trên máy tính của bạn được quyết định bởi trình điều khiển và HĐH. Chúng ta có thể thoát khỏi tất cả các thuật ngữ đó vào ngày mai nếu chúng ta muốn, nhưng nguyên tắc phân phối một luồng bit có vẻ cơ bản ...
masterxilo

-1

Như anh chàng kia đã nói, một ổ cắm được xác định duy nhất bởi 4-tuple (IP khách, Cổng khách, IP máy chủ, Cổng máy chủ).

Quá trình máy chủ chạy trên Server IP duy trì cơ sở dữ liệu (có nghĩa là tôi không quan tâm loại cấu trúc dữ liệu bảng / danh sách / cây / mảng / ma thuật nào mà nó sử dụng) của các ổ cắm đang hoạt động và lắng nghe trên Cổng máy chủ. Khi nhận được tin nhắn (thông qua ngăn xếp TCP / IP của máy chủ), nó sẽ kiểm tra IP và Cổng của khách hàng dựa trên cơ sở dữ liệu. Nếu IP khách hàng và Cổng khách hàng được tìm thấy trong một mục nhập cơ sở dữ liệu, thông báo sẽ được gửi đến một trình xử lý hiện có, một mục nhập cơ sở dữ liệu mới được tạo và một trình xử lý mới xuất hiện để xử lý ổ cắm đó.

Trong những ngày đầu của ARPAnet, một số giao thức nhất định (FTP cho một) sẽ lắng nghe một cổng được chỉ định cho các yêu cầu kết nối và trả lời bằng cổng chuyển giao. Thông tin liên lạc khác cho kết nối đó sẽ đi qua cổng bàn giao. Điều này đã được thực hiện để cải thiện hiệu suất trên mỗi gói: máy tính chậm hơn vài bậc trong những ngày đó.


bạn có thể giải thích về phần 'cổng bàn giao' không?
Eli Bendersky

1
Đây là mô tả về một số giao thức tiền TCP hoặc được đơn giản hóa quá mức. Một khách hàng đang cố gắng kết nối với một ổ cắm nghe sẽ gửi một gói đặc biệt để thiết lập kết nối (bộ bit SYN). Có sự phân biệt rõ ràng giữa một gói tạo ra một ổ cắm mới và một ổ cắm sử dụng một ổ cắm hiện có.
John M

... gửi một gói đặc biệt để thiết lập kết nối (bộ bit SYN). Điều này (theo tôi hiểu) làm cho ngăn xếp giao thức cung cấp cho 'người nghe' (nếu có), đó là lý do tại sao chỉ có một cổng nghe cho mỗi kết hợp địa chỉ / cổng / giao thức. Tôi không chắc chắn nếu điều này là trong thông số kỹ thuật hoặc chỉ đơn thuần là thực hiện quy ước.
Peter Wone

1
Đoạn thứ hai không mô tả chính xác những gì xảy ra ở lớp TCP hoặc trong quy trình máy chủ. Các quy trình máy chủ không cần duy trì cấu trúc dữ liệu của ổ cắm dưới bất kỳ hình thức nào hoặc để kiểm tra IP đến: các cặp cổng chống lại bất cứ điều gì. Đó là những gì ổ cắm ở đó cho. FTP sử dụng một cổng riêng cho dữ liệu, không phải cho tất cả 'thông tin liên lạc' và mũ được thực hiện để đơn giản hóa giao thức, không phải vì lý do hiệu suất. Sử dụng một cổng mới trong khi không cải thiện hiệu suất theo bất kỳ cách nào.
Hầu tước Lorne

"duy trì cơ sở dữ liệu (có nghĩa là tôi không quan tâm loại cấu trúc dữ liệu bảng / danh sách / cây / mảng / ma thuật nào mà nó sử dụng)" :) Tôi thường gọi đây là "Bảng" (hoặc có thể là "Biểu đồ" hoặc "Cây quyết định" ). "Cơ sở dữ liệu" gợi ý một số triển khai với tôi.
masterxilo
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.