2010-11-23 26 views
9

Như bạn đã biết sendmsg có tuyên bố này:Cách sendmsg hoạt động?

int sendmsg(int s, const struct msghdr *msg, int flags);

msghdr cấu trúc có dạng như sau:

struct msghdr { 
    void   * msg_name;  /* optional address */ 
    socklen_t msg_namelen; /* size of address */ 
    struct iovec * msg_iov;  /* scatter/gather array */ 
    size_t  msg_iovlen;  /* # elements in msg_iov */ 
    void   * msg_control; /* ancillary data, see below */ 
    socklen_t msg_controllen; /* ancillary data buffer len */ 
    int   msg_flags;  /* flags on received message */ 
}; 

Như bạn thấy msghdr có một loạt các bộ đệm, iovec và có bộ đệm msg_iovlen. Những gì tôi tự hỏi là làm thế nào sendmsg gửi các bộ đệm. Nó có nối tất cả các bộ đệm và gửi hay gửi nó trong vòng lặp for?

+4

Chỉ cần lưu ý: nếu điều này là dành cho sự tò mò, sau đó làm mát. Nếu bạn đang cố gắng viết cái gì đó phụ thuộc vào kiến ​​thức này, thì bạn gần như chắc chắn làm điều đó sai và yêu cầu rắc rối. –

+2

@SanJacinto nó sẽ hữu ích cho bạn để xây dựng trên ** lý do tại sao ** viết một cái gì đó mà phụ thuộc vào kiến ​​thức này là yêu cầu cho sự cố. Bạn có thể xây dựng được không? –

+1

@lori Vì tài liệu cung cấp cho bạn một bộ giao diện mã và cho bạn biết những gì mong đợi từ chúng. Các giao diện rất chậm để thay đổi. Mã cơ bản không có bảo đảm như vậy. Nếu bạn đang thu thập kiến ​​thức về nội bộ và viết mã của bạn xung quanh kiến ​​thức đó, thì bạn không nên ngạc nhiên nếu bạn cập nhật hạt nhân hoặc một số trình điều khiển trên ngăn xếp mạng và mã của bạn gọi nó không hoạt động nữa. Bạn đã thực hiện một sự lựa chọn tồi nếu bạn đã làm điều này. –

Trả lời

22

Các manpage nói về một tin nhắn (số ít) và nhiều yếu tố (số nhiều):

Đối send()sendto(), thông điệp được tìm thấy trong buf và có chiều dài len. Đối với sendmsg(), thông báo được trỏ đến bởi các phần tử của mảng msg.msg_iov. Cuộc gọi sendmsg() cũng cho phép gửi dữ liệu phụ trợ (còn được gọi là thông tin điều khiển).

Đối với ổ cắm luồng, điều đó cũng không thành vấn đề. Mọi dữ liệu bạn gửi sẽ chỉ kết thúc dưới dạng một luồng dữ liệu dài ở phía bên kia.

Đối với datagram hoặc ổ cắm tin nhắn, tôi có thể thấy lý do tại sao rõ ràng hơn một chút sẽ hữu ích. Nhưng có vẻ như bạn chỉ gửi một gói dữ liệu hoặc tin nhắn với một cuộc gọi sndmsg duy nhất; không một phần tử đệm.

Tôi thực sự đã đào bới mã nguồn Linux ra khỏi sự tò mò và để có được cảm giác tốt hơn về câu trả lời này. Có vẻ như sendsendto chỉ là trình bao bọc cho sendmsg trong Linux, xây dựng struct msghdr cho bạn. Và trên thực tế, triển khai UDP sendmsg tạo chỗ cho một tiêu đề UDP UDP cho mỗi cuộc gọi sendmsg.

Nếu hiệu suất là những gì bạn đang lo lắng, có vẻ như bạn sẽ không được hưởng lợi từ số sendmsg nếu bạn vượt qua chỉ một iovec. Tuy nhiên, nếu bạn đang ghép nối bộ đệm trong không gian người dùng, điều này có khả năng sẽ giúp bạn giành được một số.

Nó hơi giống với writev, với lợi ích bổ sung mà bạn có thể chỉ định địa chỉ đích để sử dụng với ổ cắm không kết nối như UDP. Bạn cũng có thể thêm dữ liệu phụ trợ, nếu bạn đang vào loại điều đó.(Thường được sử dụng để gửi các bộ mô tả tệp trên các ổ cắm miền UNIX.)

+0

Nếu tôi đã đọc mã SCTP ngay (SCTP hỗ trợ SOCK_SEQPACKET ổ cắm), nó cũng là 1 SCTP tin nhắn cho mỗi cuộc gọi sendmsg. Nó cũng tương tự cho các ổ cắm AF_UNIX SEQPACKET. – ninjalj

+0

"Nếu thông báo quá dài để vượt qua nguyên tắc thông qua giao thức cơ bản, lỗi EMSGSIZE được trả về và thư không được truyền đi". (http://linux.die.net/man/2/sendmsg) - đây không phải là đặc điểm kỹ thuật chính xác cho những gì linux thực hiện trong các ổ cắm UDP/gói ("nguyên tử"!)? Hoặc cách khác vòng, nếu Linux đã làm một cái gì đó khác nhau, nó sẽ không thất bại các đặc điểm kỹ thuật? – Aconcagua

+0

@Aconcagua Tôi nghĩ bạn đang xem xét điều gì đó khác biệt. Công cụ 'iovec' là về việc ghép nối một loạt các bộ đệm và gửi chúng dưới dạng một thông báo. 'EMSGSIZE' là cái gì đó có thể xảy ra sau quá trình xử lý đó, nếu tổng số thông báo vượt quá một số giới hạn giao thức. –

1

Theo http://opengroup.org/onlinepubs/007908799/xns/sendmsg.html ...

Các dữ liệu từ mỗi khu vực lưu trữ chỉ định bởi msg_iov được gửi lần lượt.

Giải thích của tôi là sendmsg() sẽ không nối dữ liệu thư được lưu trữ trong iovec; mỗi tin nhắn sẽ được gửi dưới dạng tin nhắn riêng.

[Chỉnh sửa: Giải thích của tôi không chính xác; . Thấy câu trả lời khác cho một lời giải thích tốt hơn]

+1

Xin lỗi, nhưng điều này không chính xác trong trường hợp chung. Ví dụ, trên Linux, iovec được ghép nối trong hạt nhân trong 'proto_ops-> sendmsg()'. – ninjalj

+0

..và đặc biệt, nếu bạn sử dụng 'sendmsg()' trên ổ cắm 'SOCK_DGRAM', bạn sẽ nhận được * một * datagram với dữ liệu từ tất cả các iovec. – caf

+0

Tôi đã sửa chữa; Cảm ơn bạn đã làm rõ. – Kamal

1

Nó phụ thuộc vào ngăn xếp TCP/IP của bạn. Các ngăn xếp TCP/IP được nhúng có thể gửi trực tiếp các iovec khác nhau tới NIC. Nhưng trên các ngăn xếp TCP/IP thông thường, phải có một bản sao từ bộ nhớ không gian người dùng đến bộ nhớ kernelspace, vì vậy không có ở đó, và iovec được sao chép khái niệm vào một bộ nhớ lớn (nó có thể là các trang bộ nhớ riêng biệt, nếu trình điều khiển hỗ trợ scather/thu thập I/O, nhưng phần quan trọng ở đây là ranh giới iovec không được bảo toàn).

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