1. 程式人生 > >Linux\Unix IPC程序通訊例項分析(一):共享記憶體通訊---系統V

Linux\Unix IPC程序通訊例項分析(一):共享記憶體通訊---系統V

前些天看到有個博主寫部落格採用問答式的敘述方法:把很多知識點通過一問一答的形式把文章串起來,我覺得這種形式不錯,便於突出重點。後面我也做下嘗試,一邊寫寫部落格,一邊回顧一下自己對IPC程序通訊的認識。

Q:這些例子來自哪?

Q:IBM原文都寫過了,為什麼還要在這裡再寫一遍?

A:IBM原文挺經典的,我這裡還是建議大家看看,但是原文例子有些編譯不通過的地方,需要做適當修改才能執行。另外那些例子比較早了,在現在的系統上執行結果不一定和文章描述一致。最後就是,原文對例子中的語句註釋不夠詳細,不如再寫一遍,加深對例子的認識,同時多學習點程式設計知識。

Q:程式碼裡怎麼那麼多註釋?

A:我本來想少寫點註釋的,並且打算用自己的話寫,不過我發現系統程式設計手冊給的解釋特別好,而且已經很精簡了,其他網站給的說明還沒有手冊的完整,所以乾脆直接貼手冊的內容吧。所以會看到註釋比程式碼還多。。。,如果你不想看註釋,直接把程式碼粘到本地,刪除註釋就一目瞭然了。

Q:例子能保證編譯麼,可以開始了?

A:都是自己編譯通過的,讓我們開始吧~

IPC共享記憶體-----系統V方式程式設計例項

該例項包含兩個程式:map_v_write.cpp和map_v_read.cpp,分別編譯後先建立一個檔名為myshm,這個檔案是生成IPC KEY而用的,程式碼裡有描述。之後先執行write程式,再執行read程式,觀察結果。 

/* 檔案:map_v_write.cpp
   描述:和map_v_read.cpp檔案配合完成系統V共享記憶體程式設計實驗
 */
//#include <sys/ipc.h>
//#include <sys/types.h>//註釋掉的兩個標頭檔案是IPC最基本的,但在shm.h中include過了
#include <sys/shm.h>//系統V共享記憶體函式shmget shmat shmdt

#include <string.h>//memcpy
#include <stdio.h>//perror
#include <errno.h>//errno

//共享記憶體通訊多采用結構體資料表達資訊,任意定義
typedef struct{
    char name[4];
    int age;
}people;

main(int argc, char** argv)
{
    int shm_id,i;
    key_t key;//儲存ftok函式返回值
    char temp;
    people *p_map;

    //建立IPC鍵值
    char* name = "./myshm";//務必指定存在的檔案
    key = ftok(name, 1);//引數儘量別用0
/*   man ftok:

NAME
     ftok - generate an IPC key

SYNOPSIS
     #include <sys/ipc.h>

     key_t ftok(const char *path, int id);

DESCRIPTION
     The ftok() function returns a key based on path and id  that
     is  usable  in  subsequent calls to msgget(2), semget(2) and
     shmget(2). The path argument must  be  the  pathname  of  an
     existing file that the process is able to  stat(2).

     The ftok() function will return the same key value  for  all
     paths  that name the same file, when called with the same id
     value, and will return different key values when called with
     different id values.

     If the file named by path is removed while still referred to
     by a key, a call to ftok() with the same path and id returns
     an error. If the same file is  recreated,  then  a  call  to
     ftok()  with the same path and id is likely to return a dif-
     ferent key.

     Only the low  order  8-bits  of  id  are  significant.   The
     behavior of ftok() is unspecified if these bits are 0.

RETURN VALUES
     Upon successful completion, ftok() returns  a  key.   Other-
     wise,  ftok()  returns  (key_t)-1 and sets errno to indicate
     the error.
*/
    perror("ftok:");//列印errno, 參考附錄errno定義
/*  man perror

NAME
     perror, errno - print system error messages

SYNOPSIS
     #include <stdio.h>

     void perror(const char *s);
     #include <errno.h>
     int errno;

DESCRIPTION
     The perror() function produces a  message  on  the  standard
     error  output  (file descriptor 2) describing the last error
     encountered during a call to a system or  library  function.
     The  argument string s is printed, followed by a colon and a
     blank, followed by the message and a NEWLINE character.   If
     s is a null pointer or points to a null string, the colon is
     not printed. The argument string should include the name  of
     the  program  that  incurred  the error. The error number is
     taken from the external variable errno, which  is  set  when
     errors  occur  but  not cleared when non-erroneous calls are
     made. See  intro(2).

*/

    //獲取共享記憶體ID
    shm_id=shmget(key,4096,IPC_CREAT|00666);//give the permissions
    perror("shmget:");
/*  man shmget:

NAME
     shmget - get shared memory segment identifier

SYNOPSIS
     #include <sys/types.h>
     #include <sys/ipc.h>
     #include <sys/shm.h>

     int shmget(key_t key, size_t size, int shmflg);

DESCRIPTION
     The shmget() function returns the shared  memory  identifier
     associated with key.

     A shared memory identifier and associated data structure and
     shared  memory segment of at least size bytes (see intro(2))
     are created for key if one of the following are true:

        o  The key argument is equal to IPC_PRIVATE.

        o  The key argument does not already have a shared memory
           identifier  associated with it, and (shmflg&IPC_CREAT)
           is true.

     Upon creation, the data structure associated  with  the  new
     shared memory identifier is initialized as follows:

        o  The    values    of    shm_perm.cuid,    shm_perm.uid,
           shm_perm.cgid,  and  shm_perm.gid are set equal to the
           effective user ID  and  effective  group  ID,  respec-
           tively, of the calling process.

        o  The access permission bits of  shm_perm.mode  are  set
           equal   to  the  access  permission  bits  of  shmflg.
           shm_segsz is set equal to the value of size.

        o  The values  of  shm_lpid,  shm_nattch  shm_atime,  and
           shm_dtime are set equal to 0.

        o  The shm_ctime is set equal to the current time.

     Shared memory segments must be explicitly removed after  the
     last reference to them has been removed.

RETURN VALUES
     Upon   successful   completion,   a   non-negative   integer
     representing  a shared memory identifier is returned. Other-
     wise, -1 is returned and errno is set to indicate the error.
*/

    p_map=(people*)shmat(shm_id,NULL,0);
    perror("shmat:");
/*
NAME
     shmop, shmat, shmdt - shared memory operations

SYNOPSIS
     #include <sys/types.h>
     #include <sys/shm.h>

     void *shmat(int shmid, const void *shmaddr, int shmflg);

  Default
     int shmdt(char *shmaddr);

  Standard conforming
     int shmdt(const void *shmaddr);

DESCRIPTION
     The shmat() function  attaches  the  shared  memory  segment
     associated  with  the  shared memory identifier specified by
     shmid to the data segment of the calling process.    
*/    
    //往記憶體寫入資料
    temp='a';
    for(i = 0;i<10;i++)
    {
        temp+=1;
        memcpy((*(p_map+i)).name,&temp,1);
        (*(p_map+i)).age=20+i;
    }

    //unlink共享記憶體
    shmdt((char*)p_map);//這裡可以去掉char*編譯試試,我這裡去掉後編譯不通過,待研究
    perror("shmdt:");
/*
     The shmdt() function detaches  from  the  calling  process's
     data  segment  the  shared  memory  segment  located  at the
     address  specified  by  shmaddr.  If  the   application   is
     standard-conforming (see standards(5)), the shmaddr argument
     is of type const void *. Otherwise it is of type char *.
*/

}

讀端的程式用到的API和寫端一樣,就略去註釋了

/* 檔案:map_v_read.cpp
   描述:和map_v_write.cpp檔案配合完成系統V共享記憶體程式設計實驗
 */
#include <sys/shm.h>
#include <unistd.h>

#include <string.h>
#include <stdio.h>

//讀端程式要和寫端程式保持一致,這樣才能互相通訊
//定義資料結構
typedef struct{
    char name[4];
    int age;
} people;

main(int argc, char** argv)
{
    int shm_id,i;
    key_t key;
    people *p_map;
    
    //create shm file and get key
    char* name = "./myshm";
    key = ftok(name,1);
    perror("ftok:");
    
    //get shm
    shm_id = shmget(key,4096,IPC_CREAT);
    perror("shmget:");
    
    //link the shm
    p_map = (people*)shmat(shm_id,NULL,0);
    perror("shmat:");
    for(i = 0;i<10;i++)
    {
        printf( "name:%s\n",(*(p_map+i)).name );
        printf( "age %d\n",(*(p_map+i)).age );
    }
    
    //unlink
    shmdt((char*)p_map);
    perror("shmdt:");
}


 最後貼一下errno.h定義,據此可以找到錯誤原因

#define EPERM   1       /* Not super-user                       */
#define ENOENT  2       /* No such file or directory            */
#define ESRCH   3       /* No such process                      */
#define EINTR   4       /* interrupted system call              */
#define EIO     5       /* I/O error                            */
#define ENXIO   6       /* No such device or address            */
#define E2BIG   7       /* Arg list too long                    */
#define ENOEXEC 8       /* Exec format error                    */
#define EBADF   9       /* Bad file number                      */
#define ECHILD  10      /* No children                          */
#define EAGAIN  11      /* Resource temporarily unavailable     */
#define ENOMEM  12      /* Not enough core                      */
#define EACCES  13      /* Permission denied                    */
#define EFAULT  14      /* Bad address                          */
#define ENOTBLK 15      /* Block device required                */
#define EBUSY   16      /* Mount device busy                    */
#define EEXIST  17      /* File exists                          */
#define EXDEV   18      /* Cross-device link                    */
#define ENODEV  19      /* No such device                       */
#define ENOTDIR 20      /* Not a directory                      */
#define EISDIR  21      /* Is a directory                       */
#define EINVAL  22      /* Invalid argument                     */
#define ENFILE  23      /* File table overflow                  */
#define EMFILE  24      /* Too many open files                  */
#define ENOTTY  25      /* Inappropriate ioctl for device       */
#define ETXTBSY 26      /* Text file busy                       */
#define EFBIG   27      /* File too large                       */
#define ENOSPC  28      /* No space left on device              */
#define ESPIPE  29      /* Illegal seek                         */
#define EROFS   30      /* Read only file system                */
#define EMLINK  31      /* Too many links                       */
#define EPIPE   32      /* Broken pipe                          */
#define EDOM    33      /* Math arg out of domain of func       */
#define ERANGE  34      /* Math result not representable        */
#define ENOMSG  35      /* No message of desired type           */
#define EIDRM   36      /* Identifier removed                   */
#define ECHRNG  37      /* Channel number out of range          */
#define EL2NSYNC 38     /* Level 2 not synchronized             */
#define EL3HLT  39      /* Level 3 halted                       */
#define EL3RST  40      /* Level 3 reset                        */
#define ELNRNG  41      /* Link number out of range             */
#define EUNATCH 42      /* Protocol driver not attached         */
#define ENOCSI  43      /* No CSI structure available           */
#define EL2HLT  44      /* Level 2 halted                       */
#define EDEADLK 45      /* Deadlock condition.                  */
#define ENOLCK  46      /* No record locks available.           */
#define ECANCELED 47    /* Operation canceled                   */
#define ENOTSUP 48      /* Operation not supported              */

/* Filesystem Quotas */
#define EDQUOT  49      /* Disc quota exceeded                  */

/* Convergent Error Returns */
#define EBADE   50      /* invalid exchange                     */
#define EBADR   51      /* invalid request descriptor           */
#define EXFULL  52      /* exchange full                        */
#define ENOANO  53      /* no anode                             */
#define EBADRQC 54      /* invalid request code                 */
#define EBADSLT 55      /* invalid slot                         */
#define EDEADLOCK 56    /* file locking deadlock error          */

#define EBFONT  57      /* bad font file fmt                    */

/* Interprocess Robust Locks */
#define EOWNERDEAD      58      /* process died with the lock */
#define ENOTRECOVERABLE 59      /* lock is not recoverable */

/* stream problems */
#define ENOSTR  60      /* Device not a stream                  */
#define ENODATA 61      /* no data (for no delay io)            */
#define ETIME   62      /* timer expired                        */
#define ENOSR   63      /* out of streams resources             */

#define ENONET  64      /* Machine is not on the network        */
#define ENOPKG  65      /* Package not installed                */
#define EREMOTE 66      /* The object is remote                 */
#define ENOLINK 67      /* the link has been severed            */
#define EADV    68      /* advertise error                      */
#define ESRMNT  69      /* srmount error                        */

#define ECOMM   70      /* Communication error on send          */
#define EPROTO  71      /* Protocol error                       */

/* Interprocess Robust Locks */
#define ELOCKUNMAPPED   72      /* locked lock was unmapped */

#define ENOTACTIVE 73   /* Facility is not active               */
#define EMULTIHOP 74    /* multihop attempted                   */
#define EBADMSG 77      /* trying to read unreadable message    */
#define ENAMETOOLONG 78 /* path name is too long                */
#define EOVERFLOW 79    /* value too large to be stored in data type */
#define ENOTUNIQ 80     /* given log. name not unique           */
#define EBADFD  81      /* f.d. invalid for this operation      */
#define EREMCHG 82      /* Remote address changed               */

/* shared library problems */
#define ELIBACC 83      /* Can't access a needed shared lib.    */
#define ELIBBAD 84      /* Accessing a corrupted shared lib.    */
#define ELIBSCN 85      /* .lib section in a.out corrupted.     */
#define ELIBMAX 86      /* Attempting to link in too many libs. */
#define ELIBEXEC 87     /* Attempting to exec a shared library. */
#define EILSEQ  88      /* Illegal byte sequence.               */
#define ENOSYS  89      /* Unsupported file system operation    */
#define ELOOP   90      /* Symbolic link loop                   */
#define ERESTART 91     /* Restartable system call              */
#define ESTRPIPE 92     /* if pipe/FIFO, don't sleep in stream head */
#define ENOTEMPTY 93    /* directory not empty                  */
#define EUSERS  94      /* Too many users (for UFS)             */

/* BSD Networking Software */
        /* argument errors */
#define ENOTSOCK        95      /* Socket operation on non-socket */
#define EDESTADDRREQ    96      /* Destination address required */
#define EMSGSIZE        97      /* Message too long */
#define EPROTOTYPE      98      /* Protocol wrong type for socket */
#define ENOPROTOOPT     99      /* Protocol not available */
#define EPROTONOSUPPORT 120     /* Protocol not supported */
#define ESOCKTNOSUPPORT 121     /* Socket type not supported */
#define EOPNOTSUPP      122     /* Operation not supported on socket */
#define EPFNOSUPPORT    123     /* Protocol family not supported */
#define EAFNOSUPPORT    124     /* Address family not supported by */
                                /* protocol family */
#define EADDRINUSE      125     /* Address already in use */
#define EADDRNOTAVAIL   126     /* Can't assign requested address */
        /* operational errors */
#define ENETDOWN        127     /* Network is down */
#define ENETUNREACH     128     /* Network is unreachable */
#define ENETRESET       129     /* Network dropped connection because */
                                /* of reset */
#define ECONNABORTED    130     /* Software caused connection abort */
#define ECONNRESET      131     /* Connection reset by peer */
#define ENOBUFS         132     /* No buffer space available */
#define EISCONN         133     /* Socket is already connected */
#define ENOTCONN        134     /* Socket is not connected */
/* XENIX has 135 - 142 */
#define ESHUTDOWN       143     /* Can't send after socket shutdown */
#define ETOOMANYREFS    144     /* Too many references: can't splice */
#define ETIMEDOUT       145     /* Connection timed out */
#define ECONNREFUSED    146     /* Connection refused */
#define EHOSTDOWN       147     /* Host is down */
#define EHOSTUNREACH    148     /* No route to host */
#define EWOULDBLOCK     EAGAIN
#define EALREADY        149     /* operation already in progress */
#define EINPROGRESS     150     /* operation now in progress */

/* SUN Network File System */
#define ESTALE          151     /* Stale NFS file handle */