2010-02-19 30 views
6

Các recv() thư viện chức năng trang người đàn ông kể rằng:Trường hợp khi chặn recv() trả về ít hơn yêu cầu byte

Nó trả về số byte nhận được. Nó thường trả về bất kỳ dữ liệu có sẵn, lên đến số tiền yêu cầu, thay vì chờ đợi để nhận được số tiền đầy đủ yêu cầu.

Nếu chúng ta đang sử dụng chặn recv() cuộc gọi và yêu cầu cho 100 byte:

recv(sockDesc, buffer, size, 0); /* Where size is 100. */ 

và chỉ có 50 byte được gửi bởi máy chủ sau đó recv() này bị chặn cho đến 100 byte có sẵn hoặc nó sẽ trở lại nhận 50 byte.

Kịch bản có thể là:

  • máy chủ bị treo sau khi sendign chỉ có 50 byte

  • thiết kế giao thức xấu nơi máy chủ được chỉ gửi 50 byte trong khi khách hàng đang mong đợi 100 và máy chủ cũng đang chờ đợi phản hồi của khách hàng (nghĩa là kết nối đóng socket chưa được khởi tạo bởi máy chủ trong đó recv sẽ trở về)

Tôi quan tâm đến Li nền tảng nux/Solaris. Tôi không có môi trường phát triển để tự mình kiểm tra.

Trả lời

13

recv sẽ trở lại khi có dữ liệu trong bộ đệm trong để quay lại. Nó sẽ không đợi cho đến khi có 100 byte nếu bạn yêu cầu 100 byte.

Nếu bạn đang gửi 100 byte "thư", hãy nhớ rằng TCP không cung cấp thư, đó chỉ là luồng. Nếu bạn đang xử lý các thông điệp ứng dụng, bạn cần phải xử lý nó ở tầng ứng dụng vì TCP sẽ không làm điều đó.

Có nhiều, nhiều điều kiện trong đó cuộc gọi send() 100 byte có thể không được đọc đầy đủ ở đầu kia chỉ với một cuộc gọi recv khi gọi recv (..., 100); đây chỉ là một vài ví dụ:

  • Việc gửi TCP stack quyết định bó cùng nhau 15 ghi cuộc gọi, và MTU xảy ra là 1460, trong đó - tùy thuộc vào thời gian của dữ liệu đến có thể gây ra các khách hàng đầu tiên 14 các cuộc gọi để tìm nạp 100 byte và lệnh gọi để tìm nạp 60 byte - 40 byte cuối cùng sẽ đến vào lần tiếp theo bạn gọi recv().(Nhưng nếu bạn gọi recv với bộ đệm là 100, bạn có thể nhận được 40 byte cuối cùng của thông báo "ứng dụng" trước đó và 60 byte đầu tiên của thông báo tiếp theo)

  • Bộ đệm người gửi đầy, có thể người đọc chậm hoặc mạng bị tắc nghẽn. Tại một số thời điểm, dữ liệu có thể đi qua và trong khi làm trống vùng đệm dữ liệu cuối cùng không phải là bội số của 100.

  • Bộ đệm nhận đầy, trong khi ứng dụng của bạn recv() dữ liệu, đoạn cuối cùng kéo lên chỉ là một phần vì toàn bộ 100 byte của thông điệp đó không phù hợp với bộ đệm.

Nhiều trường hợp này khá khó kiểm tra, đặc biệt trên làn đường nơi bạn có thể không bị tắc nghẽn hoặc mất gói dữ liệu - mọi thứ có thể khác nhau khi bạn tăng tốc độ gửi tin nhắn/được sản xuất.

Dù sao đi nữa. Nếu bạn muốn đọc 100 byte từ một ổ cắm, sử dụng giống như

int 
readn(int f, void *av, int n) 
{ 
    char *a; 
    int m, t; 

    a = av; 
    t = 0; 
    while(t < n){ 
     m = read(f, a+t, n-t); 
     if(m <= 0){ 
      if(t == 0) 
       return m; 
      break; 
     } 
     t += m; 
    } 
    return t; 
} 

...

if(readn(mysocket,buffer,BUFFER_SZ) != BUFFER_SZ) { 
    //something really bad is going on. 

} 
+0

Cảm ơn bạn đã giải thích chi tiết. Chỉ cần xác nhận nếu điều này là đúng cho * chặn * recv() gọi là tốt? (ví dụ: recv() trả lại với số byte nhỏ hơn yêu cầu) – Adil

+0

Có, điều này đúng với cuộc gọi chặn cuộc gọi. – nos

2

Nếu bạn đọc báo giá một cách chính xác, các kịch bản phổ biến nhất là:

  • ổ cắm đang nhận dữ liệu. 100 byte đó sẽ mất một thời gian.
  • cuộc gọi recv() được thực hiện.
    • Nếu có nhiều hơn 0 byte trong bộ đệm, recv() trả về những gì có sẵn và không đợi.
    • Trong khi có sẵn 0 byte khối và độ chi tiết của hệ thống luồng xác định khoảng thời gian đó là bao nhiêu.
+0

Cảm ơn vì vậy nó có nghĩa là nếu chặn recv() được phát hành và dữ liệu có sẵn (ít hơn yêu cầu), nó sẽ trở lại với bất kỳ dữ liệu nào có sẵn. đúng? – Adil

7

Các hành vi được xác định bởi hai điều. Các recv thấp nước đánh dấu và có hay không bạn vượt qua các MSG_WAITALL cờ. Nếu bạn vượt qua cờ này, cuộc gọi sẽ chặn cho đến khi số byte được yêu cầu được nhận, ngay cả khi máy chủ bị treo. Khác khôn ngoan nó trả về ngay sau khi ít nhất SO_RCVLOWAT byte có sẵn trong bộ đệm nhận của socket.

SO_RCVLOWAT

Thiết lập số lượng tối thiểu của byte để quá trình cho các hoạt động ổ cắm đầu vào. Giá trị mặc định cho SO_RCVLOWAT là 1. Nếu SO_RCVLOWAT được đặt thành giá trị lớn hơn, chặn nhận cuộc gọi bình thường đợi cho đến khi nhận được nhỏ hơn giá trị đánh dấu nước thấp hoặc số tiền được yêu cầu. (Chúng có thể trả lại ít hơn vạch nước thấp nếu xảy ra lỗi , tín hiệu bị bắt hoặc loại dữ liệu tiếp theo trong hàng đợi khác với số được trả về, ví dụ: dữ liệu ngoài băng). Tùy chọn này có giá trị int. Lưu ý rằng không phải tất cả các triển khai đều cho phép tùy chọn này là .

+0

SO_RCVLOWAT là tùy chọn ổ cắm. nếu chúng ta không thiết lập bất kỳ tùy chọn socket nào và không có flag nào được chuyển tới recv(), và việc chặn cuộc gọi recv() được phát hành, nó sẽ chờ tất cả các byte được yêu cầu? (Thao tác đóng socket cũng không được kết nối) – Adil

+1

Trong trường hợp bạn mô tả trong bài đăng của mình, nó sẽ trả về 50 byte. Nó sẽ ** không ** chờ 100 byte đầy đủ trừ khi bạn chuyển cờ 'MSG_WAITALL' sang' recv'. –

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