2012-04-01 20 views
7

tôi đang cố gắng để tạo ra một liệu ổ cắm bằng Python mà lắng nghe cho chỉ gói UDP:Ổ cắm nguyên gốc của Python lắng nghe các gói UDP; chỉ một nửa trong số các gói tin nhận được

import socket 
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP) 
s.bind(('0.0.0.0', 1337)) 
while True: 
    print s.recvfrom(65535) 

này cần phải được chạy như là người chủ, và tạo ra một ổ cắm nguyên trên cổng 1337 , lắng nghe các gói UDP và in chúng bất cứ khi nào chúng được nhận; không có vấn đề ở đó.

Bây giờ chúng ta hãy làm một chút client để kiểm tra nếu công trình này:

import socket 
c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
c.connect(('127.0.0.1', 1337)) 
c.send('message 1') 
c.send('message 2') 
c.send('message 3') 
c.send('message 4') 
c.send('message 5') 
c.send('message 6') 

Kiên, chỉ có thông điệp đầu tiên, thứ ba, và thứ năm (message 1, message 3message 5) sẽ nhận được thông qua và được in trong máy chủ đầu ra. Các thông điệp thứ hai, thứ tư và thứ sáu không hiển thị trên đầu ra máy chủ, và thay vào đó khách hàng nhận được một ngoại lệ:

>>> c.send('message 2') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
socket.error: [Errno 111] Connection refused 

Chạy này trong Wireshark cho thấy rằng nó là nhận được một thư trả lời ICMP cho "Destination unreachable". Tôi đã có thể tái sản xuất này trên 3 máy khác nhau (tất cả chạy Linux mặc dù). Tui bỏ lỡ điều gì vậy? Đây có phải là hành vi mong đợi cho UDP để liên tục thả các gói tin, vì các giao thức sử dụng nó có nghĩa vụ phải chịu đựng sự mất gói dữ liệu? Mặc dù vậy, tại sao các gói tin sẽ bị xóa khi được gửi trên giao diện cục bộ?

Ràng buộc máy chủ là 127.0.0.1 thay vì 0.0.0.0 có cùng kết quả.

+0

Đôi khi những điều kỳ lạ xảy ra với ngăn xếp thư. Bộ điều hợp ethernet trong trường hợp này sử dụng loopback, nhưng vẫn còn, các gói "phsically" vẫn đi trên thẻ và sau đó được giải thích bởi trình điều khiển như thế nào để đặt hàng hàng đợi tin nhắn. chỉ là một số điểm nghiên cứu để giúp đỡ. – FlavorScape

+0

@Etienne, FlavorScape Tôi gặp lỗi mỗi gói khác, dường như quá thường xuyên để có lỗi mạng ... – brice

+0

Có, nó xảy ra mỗi hai gói, nghĩa là nếu bạn gửi các gói '2 * n', tất cả các gói biểu mẫu '2 * i + 1' sẽ không được thông qua. Tôi không nghĩ rằng điều này có thể được mất gói, vì đây là tất cả trên giao diện địa phương. –

Trả lời

7

Giải quyết nó theo cách ngớ ngẩn; xin vui lòng cho tôi biết nếu có một cách khác, và tôi sẽ thay đổi câu trả lời được chấp nhận.

Giải pháp đơn giản là sử dụng hai ổ cắm bị ràng buộc trên cùng một cổng; một nguyên, một không phải thô:

import socket, select 
s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
s1.bind(('0.0.0.0', 1337)) 
s2 = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP) 
s2.bind(('0.0.0.0', 1337)) 
while True: 
    r, w, x = select.select([s1, s2], [], []) 
    for i in r: 
     print i, i.recvfrom(131072) 

Điều này làm cho các gói ICMP "Không thể truy cập đích" biến mất và làm cho tất cả các gói đi qua tốt. Tôi nghĩ rằng hệ điều hành muốn một ổ cắm không thô lắng nghe trên cổng để mọi thứ diễn ra tốt đẹp, và sau đó bất kỳ ổ cắm thô nào nghe trên cùng một cổng đó sẽ nhận được các bản sao của các gói.

+0

thú vị, điều đó thực sự khá thú vị khi biết! – brice

+0

Đây chính xác là những gì tôi đang tìm kiếm! (tuy nhiên đối với Windows yêu cầu khởi tạo socket RAW hơi khác nhau) –