2012-07-18 36 views
6

Tôi gặp vấn đề với một thứ gì đó và tôi đoán đó là mã.Ổ cắm UDP Python bán ngẫu nhiên không nhận được

Ứng dụng được sử dụng để 'ping' một số thiết bị mạng tùy chỉnh được thực hiện để kiểm tra xem chúng có còn sống không. Nó ping chúng mỗi 20 giây với một gói UDP đặc biệt và mong đợi một phản hồi. Nếu họ không trả lời 3 lần ping liên tiếp, ứng dụng sẽ gửi một thông điệp cảnh báo tới nhân viên.

Ứng dụng đang chạy 24/7 và một số lần ngẫu nhiên mỗi ngày (2-5 chủ yếu) ứng dụng không nhận được gói UDP trong thời gian chính xác là 10 phút, sau đó mọi thứ trở lại bình thường. Trong 10 phút đó chỉ có 1 thiết bị dường như đang trả lời, những người khác dường như đã chết. Điều đó tôi đã có thể suy ra từ nhật ký.

Tôi đã sử dụng wireshark để đánh cắp các gói và tôi đã xác minh rằng các gói ping đang chuyển sang AND out, vì vậy phần mạng dường như hoạt động tốt, tất cả các cách tới hệ điều hành. Các máy tính đang chạy WinXPPro và một số không có tường lửa cấu hình nào. Tôi gặp sự cố này trên các máy tính khác nhau, các cài đặt cửa sổ khác nhau và các mạng khác nhau.

Tôi thực sự đang thua lỗ về những gì có thể là vấn đề ở đây.

Tôi đang đính kèm phần có liên quan của mã thực hiện tất cả mạng. Điều này được chạy trong một chuỗi riêng biệt từ phần còn lại của ứng dụng.

Tôi cảm ơn bạn trước vì bất kỳ thông tin chi tiết nào bạn có thể cung cấp.

def monitor(self): 
    checkTimer = time() 
    while self.running: 
     read, write, error = select.select([self.commSocket],[self.commSocket],[],0) 
     if self.commSocket in read: 
      try: 
       data, addr = self.commSocket.recvfrom(1024) 
       self.processInput(data, addr) 
      except: 
       pass 

     if time() - checkTimer > 20: # every 20 seconds 
      checkTimer = time() 
      if self.commSocket in write: 
       for rtc in self.rtcList: 
        try: 
         addr = (rtc, 7) # port 7 is the echo port 
         self.commSocket.sendto('ping',addr) 
         if not self.rtcCheckins[rtc][0]: # if last check was a failure 
          self.rtcCheckins[rtc][1] += 1 # incr failure count 
         self.rtcCheckins[rtc][0] = False # setting last check to failure 
        except: 
         pass 

     for rtc in self.rtcList: 
      if self.rtcCheckins[rtc][1] > 2: # didn't answer for a whole minute 
       self.rtcCheckins[rtc][1] = 0 
       self.sendError(rtc) 
+0

đừng quên rằng UDP không đảm bảo phân phối đáng tin cậy: http://en.wikipedia.org/wiki/User_Datagram_Protocol –

+0

Tôi biết điều đó, nhưng hệ thống kế thừa ở đây đang sử dụng UDP khá đáng tin cậy trong 15 năm hoặc lâu hơn và phần còn lại của hệ thống không có vấn đề như vậy. – flowInTheDark

Trả lời

3

Bạn không đề cập đến nó, vì vậy tôi phải nhắc bạn rằng vì bạn đang sử dụng select(), ổ cắm tốt hơn không bị chặn. Nếu không, recvfrom() của bạn có thể chặn. Không nên thực sự xảy ra khi xử lý đúng cách, nhưng khó có thể nói từ đoạn mã ngắn.

Sau đó, bạn không phải kiểm tra ổ cắm UDP để có thể ghi - nó luôn có thể ghi được.

Bây giờ cho vấn đề thực sự - bạn đang nói rằng các gói đang nhập vào hệ thống, nhưng mã của bạn không nhận được chúng. Điều này có lẽ là do tràn bộ đệm nhận ổ cắm. Số lượng mục tiêu ping có tăng lên trong 15 năm qua không? Bạn đang thiết lập cho mình một cơn bão ping phản ứng, và có lẽ không đọc những phản ứng đủ nhanh, do đó, họ chồng chất lên trong bộ đệm nhận và cuối cùng được giảm xuống.

gợi ý của tôi theo thứ tự ROI:

  • Spread ra yêu cầu ping, không đặt mình lên cho một DDOS. Truy vấn, giả sử, một hệ thống trên mỗi lần lặp lại và giữ thời gian kiểm tra cuối cùng cho mỗi mục tiêu. Điều này sẽ cho phép bạn thậm chí ra số lượng gói tin trong và ngoài.
  • Tăng SO_RCVBUF lên một giá trị lớn.Điều này sẽ cho phép ngăn xếp mạng của bạn xử lý tốt hơn với các gói dữ liệu.
  • Đọc các gói trong vòng lặp, tức là khi ổ cắm UDP của bạn có thể đọc được (giả sử nó không chặn), hãy đọc cho đến khi bạn nhận được EWOULDBLOCK. Điều này sẽ giúp bạn tiết kiệm được số lượng cuộc gọi select().
  • Xem liệu bạn có thể sử dụng một số API Windows nâng cao dọc theo các dòng của Linux recvmmsg(2) hay không, nếu có điều đó tồn tại, để loại bỏ nhiều gói trên mỗi syscall.

Hy vọng điều này sẽ hữu ích.

+0

Trên thực tế, ổ cắm đang ở chế độ chặn, nhưng tôi đã có một số đăng nhập tại chỗ xác nhận rằng tôi chưa bao giờ gặp sự cố đó. Đối với DDOS có thể, vấn đề này xảy ra trong các hệ thống với 4 thiết bị cũng như 20 (đó là hệ thống triển khai lớn nhất chúng tôi có) vì vậy tôi không trully tin rằng nó là một vấn đề của một DOS. Tôi sẽ đưa đề xuất của bạn vào mã và quay lại với kết quả. Cảm ơn! – flowInTheDark

+0

Làm cho bộ đệm lớn hơn không giúp đỡ, đủ kỳ quặc. Điều gì đã giúp cuối cùng là đề nghị của bạn để đọc các ổ cắm trong một vòng lặp cho đến khi EWOULDBLOCK mỗi khi tôi nhận được nó có thể đọc được. Bây giờ nó làm việc như nó phải. Cảm ơn bạn! – flowInTheDark

0

UDP không đảm bảo truyền đáng tin cậy. Điều này có thể hoạt động ngay bây giờ, trong giờ tiếp theo và vào năm tiếp theo. Sau đó, trong hai năm nó sẽ không giao tiếp được cả một giờ.

Đường dẫn của gói có thể bị chặn trong một số trường hợp. Khi điều đó xảy ra với TCP, người gửi sẽ được thông báo về sự mất mát và người gửi có thể cố gửi nó qua một tuyến đường khác. Bởi vì UDP là giao thức truyền "gửi và quên", bạn có thể mất một số gói dữ liệu của mình theo thống kê.

tl; dr Sử dụng TCP.

+1

Hãy chú ý đến phần văn bản mà tôi đề cập đến công cụ đánh dấu của tôi và xác nhận rằng các gói thực sự đã nhập vào hệ thống. – flowInTheDark

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