2009-09-11 30 views
6

tôi có thể tạo nhiều "ngắn hạn" ổ cắm ở một số mã trông giống như rằng:Có cách nào để mở lại ổ cắm không?

nb=1000 
for i in range(nb): 
    sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    sck.connect((adr, prt) 
    sck.send('question %i'%i) 
    sck.shutdown(SHUT_WR) 
    answer=sck.recv(4096) 
    print 'answer %i : %s' % (%i, answer) 
    sck.close() 

này hoạt động tốt, càng lâu càng nb là "nhỏ" đủ.

Như nb có thể là khá lớn tuy nhiên, tôi muốn làm một cái gì đó như thế này

sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sck.connect((adr, prt) 
for i in range(nb): 
    reopen(sck) # ? ? ? 
    sck.send('question %i'%i) 
    sck.shutdown(SHUT_WR) 
    answer=sck.recv(4096) 
    print 'answer %i : %s' % (%i, answer) 
sck.close() 

Vì vậy, câu hỏi là:
Có cách nào để "tái sử dụng" một ổ cắm đã được tắt ?

Trả lời

15

Không, đây là giới hạn của các ổ cắm C bên dưới (và giao thức TCP/IP, cho vấn đề đó). Câu hỏi của tôi với bạn là: tại sao bạn tắt chúng khi bạn có thể kiến ​​trúc ứng dụng của bạn sử dụng chúng?

Vấn đề với nhiều ổ cắm ngắn hạn là tắt chúng đi trong trạng thái không thể sử dụng được một thời gian (về cơ bản, gấp đôi thời gian gói, để đảm bảo bất kỳ gói nào trong mạng đến và bị loại bỏ hoặc bị hủy bỏ bởi chính mạng). Về cơ bản những gì xảy ra là, trong bộ 4 cần phải là duy nhất (nguồn ip, cổng nguồn, ip đích, cổng đích), cái đầu tiên và cuối cùng có xu hướng luôn giống nhau, khi bạn hết nguồn cổng, bạn đang hosed.

Chúng tôi đã gặp vấn đề này trong phần mềm trước khi nó chỉ trở nên rõ ràng khi chúng tôi chạy trên các máy nhanh hơn (vì chúng tôi có thể sử dụng nhiều phiên hơn).

Tại sao bạn không chỉ mở ổ cắm và tiếp tục sử dụng? Có vẻ như giao thức của bạn là một yêu cầu/phản hồi đơn giản, nên dễ dàng thực hiện được với phương pháp đó.

Cái gì như:

sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sck.connect((adr, prt) 
for i in range(nb): 
    sck.send('question %i'%i) 
    answer=sck.recv(4096) 
    print 'answer %i : %s' % (%i, answer) 
sck.close() 

Cập nhật:

Một khả năng (và chúng tôi đã làm điều này trước đó) nếu bạn đang chạy ra khỏi kết nối do mở liên tục này/đóng, là để phát hiện vấn đề và điều tiết nó. Xét đoạn mã sau (những thứ tôi đã thêm là pseudo-code hơn Python kể từ khi tôi đã không đụng Python cho khá trong một):

for i in range(nb): 
    sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    sck.connect((adr, prt) 

    while sck.error() == NO_SOCKETS_AVAIL: 
     sleep 250 milliseconds 
     sck.connect((adr, prt) 

    sck.send('question %i'%i) 
    sck.shutdown(SHUT_WR) 
    answer=sck.recv(4096) 
    print 'answer %i : %s' % (%i, answer) 
    sck.close() 

Về cơ bản, nó cho phép bạn chạy ở tốc độ cao trong khi có nhiều tài nguyên nhưng chậm lại khi bạn tấn công khu vực sự cố của mình. Đây thực sự là những gì chúng tôi đã làm cho sản phẩm của chúng tôi để "sửa chữa" vấn đề thất bại khi tài nguyên thấp. Chúng tôi sẽ tái cấu trúc nó ngoại trừ thực tế nó là một sản phẩm kế thừa gần cuối đời và chúng tôi về cơ bản ở chế độ sửa chữa với chi phí tối thiểu cho dịch vụ.

+0

Tôi ước mình có thể làm điều đó, nhưng tiếc là tôi phải tắt ổ cắm (hoặc ít nhất là "tắt máy một nửa") nếu không thì khối cuộc gọi gửi và tôi sẽ không bao giờ nhận được câu trả lời. Tôi đoán rằng nếu tôi không tắt ổ cắm, máy chủ không biết tôi đang thực hiện gửi dữ liệu và chờ đợi một số chi tiết. – dugres

+0

Bạn sẽ phải viết lại máy chủ sau đó để làm cho nó sử dụng một cách tiếp cận "hợp lý" hơn dựa trên các dấu phân cách trong luồng dữ liệu (ví dụ). Nhưng có một khả năng khác - hãy xem bản cập nhật của tôi về cách tiếp cận mà chúng tôi đã thực hiện để giải quyết vấn đề. – paxdiablo

+0

@pax: Tôi đã triển khai giải pháp của bạn và nó hoạt động rất tốt cho bất kỳ "nb" nào. Cảm ơn nhiều. – dugres

1

Nếu bạn tiếp tục mở và đóng ổ cắm cho cùng một cổng thì tốt hơn nên mở ổ cắm này một lần và giữ nó mở, sau đó bạn sẽ có hiệu suất tốt hơn nhiều, kể từ khi mở và đóng sẽ mất một thời gian.

Nếu bạn có nhiều ổ cắm ngắn hạn, bạn cũng có thể xem xét các ổ cắm datagram (UDP). Lưu ý rằng bạn không có bảo đảm khi đến trong trường hợp này, thứ tự của các gói không được bảo đảm.

3

Tôi không chắc chắn chi phí bổ sung sẽ như thế nào, nhưng bạn hoàn toàn có thể đóng và mở lại ổ cắm.Bạn cần đặt SO_REUSEADDR và ​​liên kết với một cổng cụ thể mà bạn có thể sử dụng lại.

sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sck.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
+0

Chỉ cần những gì tôi cần. Tôi quên tạo một thể hiện socket mới để mở lại. Hãy chú ý để tạo ra một trường hợp ổ cắm mới, nếu không bạn sẽ nhận được lỗi "descriptor descriptor". –

0

Bạn không thể sử dụng lại ổ cắm nhưng sẽ không giúp được gì nếu bạn đang chạy ra khỏi cổng chứ không phải ổ cắm. Mỗi cổng sẽ ở trong TIME_WAIT state gấp đôi thời gian phân đoạn tối đa sau khi bạn bắt đầu tắt máy. Tốt nhất là không yêu cầu nhiều cổng trong một thời gian ngắn như vậy, nhưng nếu bạn cần sử dụng số lượng lớn, bạn có thể tăng số ephemeral port range.

Số cổng là 16 bit và do đó chỉ có 65536 trong số đó. Nếu bạn đang sử dụng Windows hoặc Mac OS X, mặc định, các cổng tạm thời được chọn từ khoảng 49152 đến 65535. Đây là official range designated by IANA, nhưng trên Linux và Solaris (thường được sử dụng cho các máy chủ lưu lượng truy cập cao), phạm vi mặc định bắt đầu ở mức 32768 để cho phép cho nhiều cổng hơn. Bạn có thể muốn thực hiện một thay đổi tương tự cho hệ thống của bạn nếu nó chưa được thiết lập theo cách đó và bạn đang cần thêm các cổng tạm thời.

Bạn cũng có thể giảm thời gian phân đoạn tối đa trên hệ thống, giảm thời gian mỗi ổ cắm ở trạng thái TIME_WAIT hoặc sử dụng SO_REUSEADDR hoặc SO_LINGER trong một số trường hợp để sử dụng lại cổng trước khi hết hạn. Tuy nhiên, điều này ít nhất có thể gây ra các kết nối cũ hơn được trộn lẫn với các kết nối mới hơn đang sử dụng cùng một số cổng, nếu một số gói từ các kết nối cũ chậm đến, vì vậy nói chung không phải là một ý tưởng hay.

+0

Đây là một hack thực sự khủng khiếp. Tốt hơn là chỉ cần giữ ổ cắm mở và tiếp tục sử dụng nó. – Imagist

+0

Bạn chỉ có thể tiếp tục sử dụng nó nếu giao thức được thiết kế để hỗ trợ điều đó và tất cả các kết nối đến cùng một vị trí. Tất nhiên đó là tốt hơn nếu bạn có thể làm điều đó, nhưng OP nói rằng máy chủ yêu cầu kết nối phải đóng trước khi nó sẽ trả lời. – mark4o

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