2010-11-23 7 views
9

Come si sa sendmsg ha questa dichiarazione:Come funziona sendmsg?

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

e msghdr struttura ha questa forma:

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 */ 
}; 

Come si vede msghdr ha una matrice di tampone, iovec e ha buffer count msg_iovlen. Quello che mi chiedo è come sendmsg manda questi buffer. Concatena tutti i buffer e li invia o li invia in un ciclo for?

+4

Solo una nota: se questo è per curiosità, allora cool. Se stai cercando di scrivere qualcosa che dipende da questa conoscenza, allora stai quasi certamente facendo qualcosa di sbagliato e chiedendo dei problemi. –

+2

@SanJacinto sarebbe utile per voi per elaborare ** perché ** scrivere qualcosa che dipende da questa conoscenza è chiedere guai. Sei in grado di elaborare per favore? –

+1

@lori Poiché la documentazione fornisce un insieme di interfacce di codice e indica cosa aspettarsi da loro. Le interfacce sono molto lente da cambiare. Il codice sottostante non ha tale garanzia. Se stai approfondendo la conoscenza degli interni e scrivendo il tuo codice su tale conoscenza, non dovresti sorprendervi se aggiorni il tuo kernel o qualche driver sullo stack di rete e il tuo codice che chiama non funziona più. Hai fatto una scelta sbagliata se l'hai fatto. –

risposta

22

La pagina di manuale parla di un messaggio (singolare) e multiple (plurale):.

Per send() e sendto(), il messaggio si trova in buf e ha lunghezza len. Per sendmsg(), il messaggio è indicato dagli elementi dell'array msg.msg_iov. La chiamata sendmsg() consente inoltre l'invio di dati ausiliari (noti anche come informazioni di controllo).

Per una presa di corrente, non importa in alcun modo. Tutti i dati che invii finiranno semplicemente come un lungo flusso di dati sull'altro lato.

Per i socket dei datagrammi o dei messaggi, posso capire perché un po 'più di chiarezza sarebbe utile. Ma sembra che tu invii solo un datagramma o un messaggio con una singola chiamata sndmsg; non uno per elemento buffer.

In realtà ho iniziato a scavare nel codice sorgente di Linux per curiosità e per avere un'idea migliore di questa risposta. Sembra send e sendto sono solo wrapper per sendmsg in Linux, che creano lo struct msghdr per te. E infatti, l'implementazione UDP sendmsg fa spazio a un'intestazione UDP per chiamata sendmsg.

Se la prestazione è ciò di cui sei preoccupato, non sembra che tu possa beneficiare di sendmsg se passi in un solo iovec. Se si concatenano i buffer nello spazio utente, tuttavia, questo potrebbe potenzialmente farvi guadagnare un po '.

È un po 'simile a writev, con l'ulteriore vantaggio che è possibile specificare un indirizzo di destinazione da utilizzare con socket senza connessione come UDP. Puoi anche aggiungere dati ausiliari, se ti trovi in ​​quel genere di cose.(Comunemente utilizzato per inviare descrittori di file attraverso socket di dominio UNIX.)

+0

Se ho letto il codice SCTP corretto (SCTP supporta i socket SOCK_SEQPACKET), è anche 1 messaggio SCTP per chiamata sendmsg. È lo stesso anche per le prese AF_UNIX SEQPACKET. – ninjalj

+0

"Se il messaggio è troppo lungo per passare atomicamente attraverso il protocollo sottostante, viene restituito l'errore EMSGSIZE e il messaggio non viene trasmesso." (http://linux.die.net/man/2/sendmsg) - non è questa la specifica esatta di ciò che linux fa nei socket UDP/pacchetti ("atomicamente"!)? O viceversa, se Linux avesse fatto qualcosa di diverso, non avrebbe fallito la specifica? – Aconcagua

+0

@Aconcagua Penso che tu stia guardando qualcosa di diverso. La roba di 'iovec' consiste nel concatenare un gruppo di buffer e inviarli come un unico messaggio. 'EMSGSIZE' è qualcosa che potrebbe accadere dopo l'elaborazione, se il messaggio totale supera il limite del protocollo. –

1

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

I dati da ciascuna area di stoccaggio indicata dalla msg_iov vengono inviati a turno.

La mia interpretazione è che sendmsg() non si concatenare i dati del messaggio memorizzati nel iovec del; ognuno sarà inviato come messaggio separato.

[Modifica: la mia interpretazione non è corretta; Elementi vedere le altre risposte per una migliore spiegazione]

+1

Siamo spiacenti, ma nel caso generale questo non è corretto. Per esempio, su Linux, iovec viene concatenato nel kernel in 'proto_ops-> sendmsg()'. – ninjalj

+0

..e in particolare, se si utilizza 'sendmsg()' su un socket 'SOCK_DGRAM', si otterrà * un * datagramma con i dati di tutti i iecec. – caf

+0

Sono corretto; grazie per il chiarimento. – Kamal

1

Dipende dallo stack TCP/IP. Gli stack TCP/IP incorporati potrebbero potenzialmente inviare i diversi iovec direttamente alla scheda NIC. Ma sui consueti stack TCP/IP ci deve essere già una copia dalla memoria dello spazio utente alla memoria del kernelspace, quindi non vi è alcun guadagno, e iovec viene copiato concettualmente in un unico grande pezzo di memoria (può essere pagine separate di memoria, se il driver supporta scather/gather I/O, ma la parte importante qui è che i contorni iovec non vengono mantenuti).