2009-03-24 26 views
8

Tôi đang viết một cặp máy khách-máy chủ trong C++ bằng cách sử dụng ổ cắm Linux. Tôi muốn máy chủ lắng nghe kết nối và trong khi một máy khách được kết nối với máy chủ sẽ từ chối bất kỳ ứng dụng khách nào khác cố gắng kết nối.Làm cách nào để tạo một máy chủ TCP sẽ chỉ chấp nhận một kết nối tại một thời điểm?

Tôi đã thử triển khai thực hiện điều này bằng cách đặt thông số đăng nhập trong hàm listen thành 0 và 1 và không một trong các giá trị đó có vẻ hoạt động. Khách hàng đầu tiên kết nối như mong đợi, nhưng bất kỳ khách hàng tiếp theo nào chỉ chặn trong khi khách hàng đầu tiên kết thúc. Điều gì thực sự gây nhầm lẫn với tôi là họ không chặn kết nối với máy chủ, họ chặn trên lần đọc đầu tiên.

Tôi đã sử dụng the code here để bắt đầu viết khách hàng và máy chủ của mình. Có ai biết những gì tôi cần phải thay đổi để có được máy chủ để chấp nhận chỉ có một kết nối khách hàng, và thả bất kỳ nỗ lực kết nối tiếp theo?

Trả lời

7

Khi bạn chấp nhận kết nối, một ổ cắm mới sẽ được tạo. Cái cũ vẫn được sử dụng để lắng nghe các kết nối trong tương lai.

Vì bạn chỉ muốn cho phép 1 kết nối tại một thời điểm, bạn chỉ có thể chấp nhận các kết nối và sau đó đóng ổ cắm mới được chấp nhận nếu bạn phát hiện bạn đang xử lý một ổ cắm khác.

Có sự khác biệt thuần mà bạn đang tìm kiếm so với việc đóng ổ cắm mới được chấp nhận ngay sau khi chấp nhận không? Máy khách sẽ biết ngay khi nó cố gắng sử dụng socket của nó (hoặc ngay lập tức nếu nó đang đợi trên máy chủ với một cuộc gọi đọc) với một lỗi cuối cùng: máy chủ chủ động đóng kết nối.

+0

Tôi đang sửa đổi mã của mình để xem tôi có thể làm điều này không. Tôi sẽ liên lạc lại với bạn ... –

+0

+1 chính xác những gì tôi sắp đề xuất. –

+0

Có vẻ là một cách tốt để đi! Tks! – LeoPucciBr

4

Chỉ cần không fork() sau accept().

Mã giả C này sẽ chỉ chấp nhận một khách hàng cùng một lúc.

while(1) { 
    listen() 
    accept() 
    *do something with the connection* 
    close() 
} 
+1

Tôi không ngã ba(). Ví dụ này là một máy chủ echo đơn giản chỉ xử lý yêu cầu. –

3

Bạn có thể đóng ổ cắm ban đầu đang nghe kết nối sau khi chấp nhận kết nối đầu tiên. Tôi không biết nếu các lớp ổ cắm bạn đang sử dụng sẽ cho phép bạn làm điều đó mặc dù.

+0

Đó là một ý tưởng, nhưng tôi muốn nó chấp nhận các kết nối mới sau khi kết nối đầu tiên được xử lý xong. –

+0

@Bill, sau đó mở lại ổ cắm khi bạn sẵn sàng chấp nhận kết nối lại. –

3

Có vẻ như bạn cần triển khai thủ công. Hãy để một khách hàng kết nối, sau đó gửi một thông báo ngắt kết nối từ máy chủ đến máy khách nếu đã có một máy khách khác được kết nối. Nếu khách hàng nhận được thông báo này, hãy để nó tự ngắt kết nối.

0

Nếu bạn có quyền kiểm soát khách hàng, bạn có thể làm cho ổ cắm không bị chặn. Trong trường hợp này, họ sẽ trả lại thông báo lỗi EINPROGRESS.

Tôi vẫn đang tìm cách thay đổi ổ cắm không bị chặn. Nếu bất cứ ai biết làm thế nào để offhand, cảm thấy tự do để chỉnh sửa câu trả lời.

0

để cho ổ cắm nghe bị chết sau khi chấp nhận và bắt đầu kết nối mới. Sau đó, khi kết nối được thực hiện, có nó quay ra một ổ cắm nghe mới.

0

Bạn có thể có các ổ cắm tùy chọn TCP_DEFER_ACCEPT bộ trên socket lắng nghe của bạn:

 
TCP_DEFER_ACCEPT (since Linux 2.4) 
    Allows a listener to be awakened only when data arrives on the socket. 
    Takes an integer value (seconds), this can bound the maximum number of 
    attempts TCP will make to complete the connection. This option should 
    not be used in code intended to be portable. 

tôi sẽ giả định nó sẽ dẫn đến tác dụng bạn mô tả, mà khách hàng kết nối không chặn trên connect, nhưng trên sau read.Tôi không chắc chắn chính xác các thiết lập tùy chọn mặc định là những gì và những gì nó cần được thiết lập để vô hiệu hóa hành vi này, nhưng có lẽ là một giá trị không là đáng thử:

int opt = 0; 
setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &opt, sizeof(opt)); 
+0

Tôi cũng đang tìm cách chỉ cho phép một kết nối tại một thời điểm. Tôi đã thử sử dụng 'setsockopt' như đã đề cập ở trên: ' int opt ​​= 0; setsockopt (sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, & opt, sizeof (opt)); ' nhưng nó không hoạt động. Vì vậy, tôi đặt 'opt' thành 1 và đã thử và nó vẫn không hoạt động. Có một số kiểm tra mà chúng tôi cần thực hiện trên 'sizeof (opt)' ở đây không? –

1

Vì bạn muốn chỉ cho phép 1 kết nối tại một thời điểm, bạn chỉ có thể chấp nhận các kết nối, và sau đó đóng ổ cắm mới được chấp nhận nếu bạn phát hiện bạn đang xử lý một ổ cắm khác.

Tôi nghĩ rằng đó phải là ổ cắm nghe được đóng. Khi kết nối đầu tiên được thiết lập, bạn đóng chốt nghe ban đầu. Và sau đó không thể thiết lập kết nối nữa.

Sau khi kết nối đầu tiên kết thúc, bạn có thể tạo một ổ cắm mới để nghe lại.

0

Theo tôi thấy, không thể nghe chính xác một kết nối.

Tcp liên quan đến bắt tay 3 chiều. Sau khi gói tin syn đầu tiên được nhận, hạt nhân đặt "kết nối" trong hàng đợi chờ, trả lời với số syn/ack và đợi cho số ack cuối cùng. Sau khi nhận được nó, nó sẽ di chuyển kết nối từ hàng đợi chờ đến hàng đợi chấp nhận, nơi nó có thể được nhận bởi ứng dụng bằng cách sử dụng cuộc gọi accept(). (Để biết chi tiết, hãy xem here.)

Trên linux, đối số tồn đọng chỉ giới hạn kích thước của hàng đợi chấp nhận. nhưng hạt nhân vẫn sẽ làm ma thuật bắt tay 3 chiều. Khách hàng nhận được syn/ack và câu trả lời với ack cuối cùng và gọi kết nối được thiết lập.

Tùy chọn duy nhất của bạn là tắt khóa nghe ngay sau khi bạn chấp nhận kết nối đầu tiên. (Tuy nhiên, điều này có thể dẫn đến kết nối khác đã có sẵn.) Hoặc bạn chủ động chấp nhận các kết nối khác và đóng chúng ngay lập tức để thông báo cho khách hàng.

Tùy chọn cuối cùng bạn có là tùy chọn bạn đã sử dụng: để cho máy chủ xếp hàng các kết nối của bạn và xử lý chúng sau cái kia. Khách hàng của bạn sẽ chặn trong trường hợp đó.

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