SysV IPC

msgsnd#

Στέλνει ένα μήνυμα σε μια ουρά μηνυμάτων System V IPC.

Η msgsnd είναι ένα λεπτό περιτύλιγμα γύρω από την κλήση συστήματος msgsnd(2). Προσαρτά το MSG στην ουρά που προσδιορίζεται από το ID (το queue id που επέστρεψε προηγουμένως η msgget), και επιστρέφει αληθές σε επιτυχία ή ψευδές σε σφάλμα με ρυθμισμένο το $!. Το MSG δεν είναι ελεύθερης μορφής: πρέπει να ξεκινά με έναν τύπο μηνύματος εγγενούς long, ακολουθούμενο από τα bytes του payload. Τα FLAGS ελέγχουν το μπλοκάρισμα και τη συμπεριφορά σφάλματος-σε-υπερχείλιση, τυπικά 0 ή IPC_NOWAIT.

Σύνοψη#

msgsnd ID, MSG, FLAGS

Τι επιστρέφεται#

Αληθές σε επιτυχία, ψευδές σε αποτυχία. Σε αποτυχία το $! τίθεται στο errno της msgsnd(2) - συνηθισμένες τιμές είναι EAGAIN (ουρά γεμάτη, τέθηκε IPC_NOWAIT), EIDRM (η ουρά αφαιρέθηκε), EINTR (σήμα διέκοψε μπλοκαριστική κλήση), και EACCES (κανένα δικαίωμα εγγραφής στην ουρά).

Επειδή η τιμή επιστροφής είναι απλή λογική τιμή, ελέγξτε την πάντα πριν υποθέσετε ότι το μήνυμα μπήκε στην ουρά:

msgsnd($qid, $msg, 0)
    or die "msgsnd($qid) failed: $!";

Μορφή μηνύματος#

Ο πυρήνας δεσμεύει τα πρώτα sizeof(long) bytes κάθε μηνύματος που μπαίνει στην ουρά για τον τύπο μηνύματος, έναν θετικό ακέραιο long που οι καλούντες της msgrcv χρησιμοποιούν για να επιλέξουν ποια μηνύματα να βγάλουν από την ουρά. Το payload ακολουθεί, χωρίς ερμηνεία.

Δημιουργήστε τον ενταμιευτή με την pack χρησιμοποιώντας τους ειδικοποιητές l! (εγγενές long) και a* (ακατέργαστα bytes):

my $type    = 1;
my $payload = "hello queue";
my $msg     = pack("l! a*", $type, $payload);
msgsnd($qid, $msg, 0) or die "msgsnd: $!";

Ο τύπος μηνύματος πρέπει να είναι μεγαλύτερος από μηδέν. Το μηδέν και οι αρνητικές τιμές είναι δεσμευμένες για τη σημασιολογία επιλογέα της msgrcv και προκαλούν αποτυχία της msgsnd(2) με EINVAL.

Καθολική κατάσταση που επηρεάζει#

  • $! - τίθεται στο errno της αποτυχημένης κλήσης συστήματος όταν η msgsnd επιστρέφει ψευδές. Ανέπαφο σε επιτυχία.

Παραδείγματα#

Αποστολή ενός απλού πληκτρολογημένου μηνύματος με την προεπιλεγμένη μπλοκαριστική συμπεριφορά. Αν η ουρά είναι γεμάτη, η κλήση περιμένει μέχρι να γίνει διαθέσιμος χώρος:

use IPC::SysV qw(IPC_PRIVATE IPC_CREAT S_IRUSR S_IWUSR);

my $qid = msgget(IPC_PRIVATE, IPC_CREAT | S_IRUSR | S_IWUSR)
    // die "msgget: $!";

my $msg = pack("l! a*", 1, "job-42");
msgsnd($qid, $msg, 0) or die "msgsnd: $!";

Αποστολή χωρίς μπλοκάρισμα - άμεση επιστροφή με EAGAIN στο $! αν η ουρά είναι γεμάτη, αντί για ύπνο:

use IPC::SysV qw(IPC_NOWAIT);
use Errno qw(EAGAIN);

unless (msgsnd($qid, $msg, IPC_NOWAIT)) {
    if ($! == EAGAIN) {
        warn "queue full, dropping message\n";
    } else {
        die "msgsnd: $!";
    }
}

Χρήση του πεδίου τύπου ως ετικέτα προτεραιότητας / καναλιού. Οι παραλήπτες επιλέγουν με βάση τον τύπο μέσω της msgrcv:

my %CHANNEL = (log => 1, metric => 2, alert => 3);

sub send_event {
    my ($kind, $body) = @_;
    my $msg = pack("l! a*", $CHANNEL{$kind}, $body);
    msgsnd($qid, $msg, 0) or die "msgsnd[$kind]: $!";
}

send_event(alert  => "disk > 90%");
send_event(metric => "rps=1240");

Αποστολή δομημένου payload - pack-άρετε τα πεδία της επικεφαλίδας μετά το υποχρεωτικό πρόθεμα τύπου:

my $type = 1;
my $body = pack("N N a*", $job_id, $retry_count, $payload);
msgsnd($qid, pack("l! a*", $type, $body), 0)
    or die "msgsnd: $!";

Οριακές περιπτώσεις#

  • Ο τύπος μηνύματος πρέπει να είναι θετικός. Το πέρασμα 0 ή αρνητικού τύπου αποτυγχάνει με EINVAL. Η σημασιολογία επιλογής τύπου στην msgrcv δεσμεύει αυτές τις τιμές για λογική επιλογέα.

  • Το μήνυμα υπερβαίνει το msg_qbytes. Αν το MSG είναι μεγαλύτερο από το ρυθμισμένο ανά-μήνυμα όριο της ουράς, η msgsnd αποτυγχάνει με EINVAL ανεξαρτήτως των FLAGS. Ελέγξτε και ανεβάστε το όριο με msgctl IPC_SET αν ελέγχετε την ουρά.

  • Ουρά γεμάτη χωρίς IPC_NOWAIT. Η κλήση μπλοκάρει μέχρι να βγάλει μήνυμα από την ουρά μια άλλη διεργασία, να αφαιρεθεί η ουρά (EIDRM), ή να την διακόψει σήμα (EINTR). Επαναλάβετε σε EINTR αν το σήμα είναι αναμενόμενο και αβλαβές.

  • Ουρά γεμάτη με IPC_NOWAIT. Αποτυγχάνει αμέσως με EAGAIN. Αυτός είναι ο μόνος τρόπος επιβολής φραγμένης καθυστέρησης στην πλευρά της αποστολής.

  • Λείπει το πρόθεμα τύπου. Η παράλειψη pack-αρίσματος του προθέματος τύπου l! περνά το ακατέργαστο payload ως έχει· τα πρώτα sizeof(long) bytes ερμηνεύονται τότε ως τύπος - τυπικά μεγάλος θετικός ή αρνητικός αριθμός - και τα υπόλοιπα ως σώμα. Οι παραλήπτες που φιλτράρουν κατά τύπο δεν βλέπουν τίποτα.

  • Το ID είναι queue id, όχι κλειδί. Περάστε τον ακέραιο που επιστρέφει η msgget, όχι το KEY που δώσατε στην msgget. Η σύγχυση μεταξύ τους οδηγεί σε EINVAL ή, χειρότερα, σε επιτυχημένη αποστολή σε άσχετη ουρά που τυχαίνει να μοιράζεται την αριθμητική τιμή.

  • Δικαιώματα. Η διεργασία πρέπει να έχει δικαίωμα εγγραφής στην ουρά (το bit w του mode της ουράς για το ενεργό uid/gid της). Διαφορετικά η κλήση αποτυγχάνει με EACCES.

  • Tainting. Το MSG διαβάζεται ως συμβολοσειρά bytes· δεν γίνεται έλεγχος taint σε αυτό εδώ. Αν το MSG προήλθε από μη έμπιστη πηγή, η πλευρά παραλήπτη (msgrcv, που όντως taint-άρει την έξοδό της) είναι εκεί όπου ανήκει το φιλτράρισμα.

Διαφορές από το upstream#

Πλήρως συμβατό με το upstream Perl 5.42.

Δείτε επίσης#

  • msgget - αποκτά το queue id που περνά ως ID· καλέστε αυτό πρώτα, ή λάβετε το id από όποιον δημιούργησε την ουρά

  • msgrcv - η αντίστοιχη πρωτογενής λειτουργία λήψης· το όρισμά της TYPE επιλέγει έναντι του προθέματος l! που γράφεται εδώ

  • msgctl - επιθεωρεί το όριο msg_qbytes της ουράς ή αφαιρεί την ουρά όταν τελειώσετε

  • pack - δημιουργία του ενταμιευτή l! a* που απαιτεί η msgsnd· επίσης το εργαλείο για οποιαδήποτε περαιτέρω δομή μέσα στο payload

  • $! - μεταφέρει το errno από αποτυχημένη msgsnd· συγκρίνετε με τις σταθερές Errno για διακλάδωση σε συγκεκριμένες αποτυχίες