Linux\Unix IPC程序通訊例項分析(一):共享記憶體通訊---系統V
阿新 • • 發佈:2019-02-12
前些天看到有個博主寫部落格採用問答式的敘述方法:把很多知識點通過一問一答的形式把文章串起來,我覺得這種形式不錯,便於突出重點。後面我也做下嘗試,一邊寫寫部落格,一邊回顧一下自己對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 */