高级Linux程序设计第五章:进程间通信
From:?http://www.cnblogs.com/forfuture1978/archive/2010/04/29/1723417.html
-  五種進(jìn)程間通信的方式:-  共享內(nèi)存(shared memory):其允許多個(gè)進(jìn)程通過(guò)讀寫(xiě)同一塊內(nèi)存地址來(lái)相互通信。
-  內(nèi)存映射(Mapped memory):其和共享內(nèi)存相似,然而它是和文件系統(tǒng)上的一個(gè)文件相關(guān)聯(lián)的。
-  管道(Pipe):其允許一個(gè)進(jìn)程到另一個(gè)相關(guān)進(jìn)程的順序通信。
-  先入先出隊(duì)列(FIFO):和管道類似,然而因?yàn)槠鋵?duì)應(yīng)于文件系統(tǒng)上的文件名,可以在兩個(gè)不相關(guān)的進(jìn)程間通信。
-  Socket:其允許在不同的計(jì)算機(jī)上的不同進(jìn)程間通信。
 
-  
1、共享內(nèi)存(Shared Memory)
-  共享內(nèi)存時(shí)進(jìn)程間通信方式中最快的一種,因?yàn)檫M(jìn)程是共享同一塊內(nèi)存。
-  內(nèi)核并不提供對(duì)共享內(nèi)存訪問(wèn)的同步機(jī)制,因而必須自己提供同步方式。
-  要用共享內(nèi)存塊,需要一個(gè)進(jìn)程首先分配此內(nèi)存塊。
-  欲訪問(wèn)共享內(nèi)存塊的進(jìn)程必須要連接到此內(nèi)存塊。
-  在使用完共享內(nèi)存塊的時(shí)候,進(jìn)程必須要卸載此內(nèi)存塊。
-  需要有一個(gè)進(jìn)程釋放此內(nèi)存塊。
-  所有的共享內(nèi)存塊都是以4KB的整數(shù)倍分配。
?
1.1、分配
-  進(jìn)程用函數(shù)shmget分配一個(gè)共享內(nèi)存塊。-  第一個(gè)參數(shù)是共享內(nèi)存塊的key-  不同的進(jìn)程可以根據(jù)此key來(lái)訪問(wèn)同一個(gè)共享內(nèi)存塊。
-  使用IPC_PRIVATE作為key會(huì)保證創(chuàng)建一個(gè)新的共享內(nèi)存塊。
-  如果多個(gè)進(jìn)程訪問(wèn)同一個(gè)共享內(nèi)存塊,則必須用同一個(gè)key。
 
-  
-  第二個(gè)參數(shù)表示內(nèi)存塊的大小。
-  第三個(gè)參數(shù)是一系列標(biāo)志位:-  IPC_CREAT創(chuàng)建一個(gè)新的內(nèi)存塊。
-  IPC_EXCL此標(biāo)志位和IPC_CREAT一起使用。如果key已經(jīng)存在,則此標(biāo)志位使得shmget失敗。
 
-  
 
-  
1.2、連接(Attachment )和卸載(Detachment)
-  一個(gè)進(jìn)程需要調(diào)用shmat來(lái)連接一個(gè)共享內(nèi)存。-  第一個(gè)參數(shù)是共享內(nèi)存塊的id,由shmget返回。
-  第二個(gè)參數(shù)是一個(gè)指針,其指向共享內(nèi)存塊映射的內(nèi)存地址,如果是NULL,則系統(tǒng)會(huì)自動(dòng)選擇一個(gè)可用的內(nèi)存地址。
-  第三個(gè)參數(shù)是標(biāo)志位:-  SHM_RND表示第二個(gè)參數(shù)所指定的地址必須同頁(yè)的大小對(duì)齊。
-  SHM_RDONLY表示此內(nèi)存塊只讀。
 
-  
-  此函數(shù)返回值是連接的共享內(nèi)存的起始地址。
 
-  
-  共享內(nèi)存塊可用函數(shù)shmdt卸載,應(yīng)傳給它共享內(nèi)存塊的起始地址。
-  調(diào)用exit及exec函數(shù)自動(dòng)卸載共享內(nèi)存塊。
?
1.3、控制和釋放共享內(nèi)存塊
-  shmctl函數(shù)可用返回和修改共享內(nèi)存塊的信息。-  第一個(gè)參數(shù)是共享內(nèi)存塊id
-  欲得到一個(gè)共享內(nèi)存塊的信息,第二個(gè)參數(shù)設(shè)為IPC_STAT,第三個(gè)參數(shù)是指向shmid_ds結(jié)構(gòu)體的指針。
-  欲刪除一個(gè)共享內(nèi)存塊,第二個(gè)參數(shù)設(shè)為IPC_RMID,第三個(gè)參數(shù)設(shè)為NULL。
 
-  
-  一個(gè)共享內(nèi)存塊在使用結(jié)束后,必須用shmctl顯式的釋放。
-  調(diào)用exit和exec自動(dòng)卸載共享內(nèi)存塊,但是不釋放。
| #include <stdio.h> #include <sys/shm.h> #include <sys/stat.h> int main () { ??? int segment_id; ??? char* shared_memory; ??? struct shmid_ds shmbuffer; ??? int segment_size; ??? const int shared_segment_size = 0x6400; ??? /* Allocate a shared memory segment. */ ??? segment_id = shmget (IPC_PRIVATE, shared_segment_size, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR); ??? /* Attach the shared memory segment. */ ??? shared_memory = (char*) shmat (segment_id, 0, 0); ??? printf (“shared memory attached at address %p\n”, shared_memory); ??? /* Determine the segment’s size. */ ??? shmctl (segment_id, IPC_STAT, &shmbuffer); ??? segment_size = shmbuffer.shm_segsz; ??? printf (“segment size: %d\n”, segment_size); ??? /* Write a string to the shared memory segment. */ ??? sprintf (shared_memory, “Hello, world.”); ??? /* Detach the shared memory segment. */ ??? shmdt (shared_memory); ??? /* Reattach the shared memory segment, at a different address. */ ??? shared_memory = (char*) shmat (segment_id, (void*) 0x5000000, 0); ??? printf (“shared memory reattached at address %p\n”, shared_memory); ??? /* Print out the string from shared memory. */ ??? printf (“%s\n”, shared_memory); ??? /* Detach the shared memory segment. */ ??? shmdt (shared_memory); ??? /* Deallocate the shared memory segment. */ ??? shmctl (segment_id, IPC_RMID, 0); ??? return 0; }? ? ipcs命令可用查看進(jìn)程間通信機(jī)制的信息 使用-m可查看共享內(nèi)存的信息 % ipcs -m ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 1627649 user 640 25600 0 ipcrm命令可刪除進(jìn)程間通信對(duì)象. % ipcrm shm 1627649 [liuchao@localhost ~]$ ipcs ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 196608 liuchao 600 393216 2 dest 0x764867bd 65537 liuchao 600 1 0 0x2c0056d5 98306 liuchao 600 1 0 0x500e7827 131075 liuchao 600 1 0 0x20e0f21d 163844 liuchao 600 1 0 0x00000000 229381 liuchao 600 393216 2 dest 0x00000000 262150 liuchao 600 393216 2 dest 0x00000000 294919 liuchao 600 393216 2 dest 0x00000000 327688 liuchao 600 393216 2 dest 0x00000000 360457 liuchao 600 393216 2 dest 0x00000000 393226 liuchao 600 393216 2 dest 0x00000000 425995 liuchao 600 393216 2 dest 0x00000000 458764 liuchao 600 393216 2 dest 0x00000000 491533 liuchao 600 393216 2 dest 0x00000000 557070 liuchao 600 393216 2 dest 0x00000000 589839 liuchao 600 393216 2 dest ------ Semaphore Arrays -------- key semid owner perms nsems 0x59d9bc4a 0 liuchao 600 1 0x3bd464f2 32769 liuchao 600 1 ------ Message Queues -------- key msqid owner perms used-bytes messages | 
?
2、進(jìn)程信號(hào)量
2.1、分配(Allocation)和釋放(Deallocation)
-  調(diào)用semget分配一個(gè)信號(hào)量,調(diào)用semctl來(lái)釋放一個(gè)信號(hào)量。
-  semget的參數(shù)為一個(gè)信號(hào)量集的key,信號(hào)量集中的信號(hào)量的個(gè)數(shù),權(quán)限標(biāo)志位,返回值為信號(hào)量集id。
-  semctl的參數(shù)為信號(hào)量集的id,信號(hào)量集中的信號(hào)量的個(gè)數(shù),IPC_RMID。
-  當(dāng)所有的使用信號(hào)量的進(jìn)程結(jié)束后,信號(hào)量仍然存在。
-  最后一個(gè)使用信號(hào)量集的進(jìn)程必須顯式的刪除它。
| #include <sys/ipc.h> #include <sys/sem.h> #include <sys/types.h> /* We must define union semun ourselves. */ union semun { ??? int val; ??? struct semid_ds *buf; ??? unsigned short int *array; ??? struct seminfo *__buf; }; /* Obtain a binary semaphore’s ID, allocating if necessary. */ int binary_semaphore_allocation (key_t key, int sem_flags) { ??? return semget (key, 1, sem_flags); } /* Deallocate a binary semaphore. All users must have finished their use. Returns -1 on failure. */ int binary_semaphore_deallocate (int semid) { ??? union semun ignored_argument; ??? return semctl (semid, 1, IPC_RMID, ignored_argument); } | 
2.2、初始化信號(hào)量
| #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> /* We must define union semun ourselves. */ union semun { ??? int val; ??? struct semid_ds *buf; ??? unsigned short int *array; ??? struct seminfo *__buf; }; /* Initialize a binary semaphore with a value of 1. */ int binary_semaphore_initialize (int semid) { ??? union semun argument; ??? unsigned short values[1]; ??? values[0] = 1; ??? argument.array = values; ??? return semctl (semid, 0, SETALL, argument); } | 
?
2.3、Wait和Post操作
-  semop函數(shù)支持wait和post操作。-  第一個(gè)參數(shù)是信號(hào)量集id。
-  第二個(gè)參數(shù)是一個(gè)sembuf結(jié)構(gòu)體的數(shù)組。
-  第三個(gè)參數(shù)是數(shù)組的長(zhǎng)度。
 
-  
-  sembuf結(jié)構(gòu)體:-  sem_num是信號(hào)量集中作為操作對(duì)象的信號(hào)量的號(hào)。
-  sem_op表示對(duì)信號(hào)量的操作。如果sem_op是正數(shù),則其將被加到信號(hào)量的值上。如果sem_op是負(fù)數(shù),則得到其絕對(duì)值,如果此值能夠使得信號(hào)量的值為負(fù),則阻塞當(dāng)前線程,直到此信號(hào)量的值等于sem_op的絕對(duì)值。如果sem_op為零,阻塞當(dāng)前線程,直到信號(hào)量的值為零。
-  sem_flg是標(biāo)志位,IPC_NOWAIT使得此操作不會(huì)被阻塞,SEM_UNDO表示當(dāng)進(jìn)程結(jié)束的時(shí)候,系統(tǒng)自動(dòng)取消此次操作。
 
-  
| #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> /* Wait on a binary semaphore. Block until the semaphore value is positive, then decrement it by 1. */ int binary_semaphore_wait (int semid) { ??? struct sembuf operations[1]; ??? /* Use the first (and only) semaphore. */ ??? operations[0].sem_num = 0; ??? /* Decrement by 1. */ ??? operations[0].sem_op = -1; ??? /* Permit undo’ing. */ ??? operations[0].sem_flg = SEM_UNDO; ??? return semop (semid, operations, 1); } /* Post to a binary semaphore: increment its value by 1. This returns immediately. */ int binary_semaphore_post (int semid) { ??? struct sembuf operations[1]; ??? /* Use the first (and only) semaphore. */ ??? operations[0].sem_num = 0; ??? /* Increment by 1. */ ??? operations[0].sem_op = 1; ??? /* Permit undo’ing. */ ??? operations[0].sem_flg = SEM_UNDO; ??? return semop (semid, operations, 1); } | 
?
3、內(nèi)存映射(Mapped Memory)
3.1、映射一個(gè)普通文件
-  使用mmap函數(shù)可將一個(gè)普通文件映射到進(jìn)程內(nèi)存中。-  第一個(gè)參數(shù)是文件將映射到的內(nèi)存地址,NULL使得Linux自動(dòng)選擇一個(gè)可用的地址。
-  第二個(gè)參數(shù)是映射的長(zhǎng)度。
-  第三個(gè)參數(shù)是映射的內(nèi)存的保護(hù)模式:PROT_READ,PROT_WRITE,PROT_EXEC。
-  第四個(gè)參數(shù)是一個(gè)標(biāo)志位:-  MAP_FIXED表示映射的內(nèi)存地址必須和頁(yè)對(duì)齊。
-  MAP_PRIVATE表示寫(xiě)入映射的內(nèi)存的數(shù)據(jù)不會(huì)寫(xiě)入關(guān)聯(lián)的文件,而是寫(xiě)入另一個(gè)文件副本,對(duì)其他線程不可見(jiàn)。
-  MAP_SHARED表示寫(xiě)入映射的內(nèi)存的數(shù)據(jù)會(huì)立即寫(xiě)入關(guān)聯(lián)的文件,不會(huì)有緩存。
 
-  
-  第五個(gè)參數(shù)是關(guān)聯(lián)文件的文件描述符。
-  第六個(gè)參數(shù)是映射的文件的偏移量。
 
-  
| (mmap-write.c) Write a Random Number to a Memory-Mapped File #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <time.h> #include <unistd.h> #define FILE_LENGTH 0x100 /* Return a uniformly random number in the range [low,high]. */ int random_range (unsigned const low, unsigned const high) { ??? unsigned const range = high - low + 1; ??? return low + (int) (((double) range) * rand () / (RAND_MAX + 1.0)); } int main (int argc, char* const argv[]) { ??? int fd; ??? void* file_memory; ??? /* Seed the random number generator. */ ??? srand (time (NULL)); ??? /* Prepare a file large enough to hold an unsigned integer. */ ??? fd = open (argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); ??? lseek (fd, FILE_LENGTH+1, SEEK_SET); ??? write (fd, “”, 1); ??? lseek (fd, 0, SEEK_SET); ??? /* Create the memory mapping. */ ??? file_memory = mmap (0, FILE_LENGTH, PROT_WRITE, MAP_SHARED, fd, 0); ??? close (fd); ??? /* Write a random integer to memory-mapped area. */ ??? sprintf((char*) file_memory, “%d\n”, random_range (-100, 100)); ??? /* Release the memory (unnecessary because the program exits). */ ??? munmap (file_memory, FILE_LENGTH); ??? return 0; } (mmap-read.c) Read an Integer from a Memory-Mapped File, and Double It #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> #define FILE_LENGTH 0x100 int main (int argc, char* const argv[]) { ??? int fd; ??? void* file_memory; ??? int integer; ??? /* Open the file. */ ??? fd = open (argv[1], O_RDWR, S_IRUSR | S_IWUSR); ??? /* Create the memory mapping. */ ??? file_memory = mmap (0, FILE_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); ??? close (fd); ??? /* Read the integer, print it out, and double it. */ ??? sscanf (file_memory, “%d”, &integer); ??? printf (“value: %d\n”, integer); ??? sprintf ((char*) file_memory, “%d\n”, 2 * integer); ??? /* Release the memory (unnecessary because the program exits). */ ??? munmap (file_memory, FILE_LENGTH); ??? return 0; } | 
3.2、共同訪問(wèn)一個(gè)文件
-  不同的進(jìn)程可以通過(guò)將同一個(gè)文件映射到內(nèi)存來(lái)通信。
-  設(shè)置MAP_SHARD使得寫(xiě)入到映射的內(nèi)存的數(shù)據(jù)會(huì)立即寫(xiě)入關(guān)聯(lián)的文件,并對(duì)另一個(gè)文件可見(jiàn)。
-  如果不做以上設(shè)定,則Linux會(huì)對(duì)數(shù)據(jù)進(jìn)行緩存,可以用函數(shù)msync將緩存寫(xiě)入文件。-  前兩個(gè)參數(shù)表示映射的內(nèi)存塊。
-  第三個(gè)參數(shù)是標(biāo)志位:-  MS_ASTYNC:寫(xiě)緩存并不立即執(zhí)行。
-  MS_SYNC:寫(xiě)緩存立即執(zhí)行。
-  MS_INVALIDATE:所有的文件映射都被刷新,可以看到最新的更新。
 
-  
 
-  
msync (mem_addr, mem_length, MS_SYNC | MS_INVALIDATE);
-  設(shè)置MAP_PRIVATE將創(chuàng)建一個(gè)寫(xiě)即復(fù)制的映射區(qū)。寫(xiě)入這些映射區(qū)的數(shù)據(jù)僅僅在當(dāng)前進(jìn)程可見(jiàn),對(duì)其他進(jìn)程不可見(jiàn)。
4、管道(Pipes)
4.1、創(chuàng)建管道
| int pipe_fds[2]; int read_fd; int write_fd; pipe (pipe_fds); read_fd = pipe_fds[0]; write_fd = pipe_fds[1]; | 
4.2、用管道來(lái)進(jìn)行子進(jìn)程和父進(jìn)程之間的通信
| #include <stdlib.h> #include <stdio.h> #include <unistd.h> /* Write COUNT copies of MESSAGE to STREAM, pausing for a second between each. */ void writer (const char* message, int count, FILE* stream) { ??? for (; count > 0; --count) { ??????? /* Write the message to the stream, and send it off immediately. */ ??????? fprintf (stream, “%s\n”, message); ??????? fflush (stream); ??????? /* Snooze a while. */ ??????? sleep (1); ??? } } /* Read random strings from the stream as long as possible. */ void reader (FILE* stream) { ??? char buffer[1024]; ??? /* Read until we hit the end of the stream. fgets reads until either a newline or the end-of-file. */ ??? while (!feof (stream) && !ferror (stream) && fgets (buffer, sizeof (buffer), stream) != NULL) ??????? fputs (buffer, stdout); } int main () { ??? int fds[2]; ??? pid_t pid; ??? /* Create a pipe. File descriptors for the two ends of the pipe are placed in fds. */ ??? pipe (fds); ??? /* Fork a child process. */ ??? pid = fork (); ??? if (pid == (pid_t) 0) { ??????? FILE* stream; ??????? /* This is the child process. Close our copy of the write end of the file descriptor. */ ??????? close (fds[1]); ??????? /* Convert the read file descriptor to a FILE object, and read from it. */ ??????? stream = fdopen (fds[0], “r”); ??????? reader (stream); ??????? close (fds[0]); ??? } ??? else { ??????? /* This is the parent process. */ ??????? FILE* stream; ??????? /* Close our copy of the read end of the file descriptor. */ ??????? close (fds[0]); ??????? /* Convert the write file descriptor to a FILE object, and write to it. */ ??????? stream = fdopen (fds[1], “w”); ??????? writer (“Hello, world.”, 5, stream); ??????? close (fds[1]); ??? } ??? return 0; } | 
4.3、用管道重定向標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出,錯(cuò)誤流。
| #include <stdio.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> int main () { ??? int fds[2]; ??? pid_t pid; ??? /* Create a pipe. File descriptors for the two ends of the pipe are placed in fds. */ ??? pipe (fds); ??? /* Fork a child process. */ ??? pid = fork (); ??? if (pid == (pid_t) 0) { ??????? /* This is the child process. Close our copy of the write end of the file descriptor. */ ??????? close (fds[1]); ??????? /* Connect the read end of the pipe to standard input. */ ??????? dup2 (fds[0], STDIN_FILENO); ??????? /* Replace the child process with the “sort” program. */ ??????? execlp (“sort”, “sort”, 0); ??? } ??? else { ??????? /* This is the parent process. */ ??????? FILE* stream; ??????? /* Close our copy of the read end of the file descriptor. */ ??????? close (fds[0]); ??????? /* Convert the write file descriptor to a FILE object, and write to it. */ ??????? stream = fdopen (fds[1], “w”); ??????? fprintf (stream, “This is a test.\n”); ??????? fprintf (stream, “Hello, world.\n”); ??????? fprintf (stream, “My dog has fleas.\n”); ??????? fprintf (stream, “This program is great.\n”); ??????? fprintf (stream, “One fish, two fish.\n”); ??????? fflush (stream); ??????? close (fds[1]); ??????? /* Wait for the child process to finish. */ ??????? waitpid (pid, NULL, 0); ?? } ?? return 0; } | 
4.4、打開(kāi)(popen)和關(guān)閉(pclose)管道
| #include <stdio.h> #include <unistd.h> int main () { ??? FILE* stream = popen (“sort”, “w”); ??? fprintf (stream, “This is a test.\n”); ??? fprintf (stream, “Hello, world.\n”); ??? fprintf (stream, “My dog has fleas.\n”); ??? fprintf (stream, “This program is great.\n”); ??? fprintf (stream, “One fish, two fish.\n”); ??? return pclose (stream); } | 
4.5、先進(jìn)先出隊(duì)列(FIFOs)
-  一個(gè)先進(jìn)先出隊(duì)列是一個(gè)管道,只不過(guò)在文件系統(tǒng)中有文件名與之對(duì)應(yīng)。
-  FIFOs又被稱為命名管道。
-  mkfifo命令可以創(chuàng)建一個(gè)FIFO
?
| % mkfifo /tmp/fifo % ls -l /tmp/fifo prw-rw-rw- 1 samuel users 0 Jan 16 14:04 /tmp/fifo | 
-  mkfifo函數(shù)可以創(chuàng)建一個(gè)FIFO
-  第一個(gè)參數(shù)是文件系統(tǒng)中的路徑。
-  第二個(gè)參數(shù)是權(quán)限。
-  訪問(wèn)FIFO和訪問(wèn)一個(gè)普通文件相同。
-  如果兩個(gè)進(jìn)程通過(guò)FIFO進(jìn)行通信,則需要一個(gè)進(jìn)程打開(kāi)一個(gè)FIFO用于寫(xiě),另一個(gè)進(jìn)程打開(kāi)同一個(gè)FIFO用于讀。
5、套接字(Sockets)
-  創(chuàng)建一個(gè)套接字:-  命名空間:PF_LOCAL和PF_UNIX表示本地命名空間,PF_INET表示互聯(lián)網(wǎng)命名空間。
-  通信方式:SOCK_STREAM表示面向連接的套接字,SOCK_DGRAM表示面向數(shù)據(jù)報(bào)的套接字。
 
-  
-  關(guān)閉套接字:close
-  連接套接字:欲在客戶端和服務(wù)器段建立連接,客戶端調(diào)用connect,指向服務(wù)器的地址,服務(wù)器端等待accept連接。
-  綁定套接字:bind,將套接字綁定到一個(gè)地址。
-  監(jiān)聽(tīng)套接字:listen,使得服務(wù)器監(jiān)聽(tīng)一個(gè)端口,等待accept一個(gè)連接。
-  接受套接字:accept,接受一個(gè)來(lái)自客戶端的連接。
?
5.1、本地命名空間套接字
訪問(wèn)同一臺(tái)機(jī)器的套接字可以使用本地命名空間:PF_LOCAL和PF_UNIX
| (socket-server.c) Local Namespace Socket Server #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> /* Read text from the socket and print it out. Continue until the socket closes. Return nonzero if the client sent a “quit” message, zero otherwise. */ int server (int client_socket) { ??? while (1) { ??????? int length; ??????? char* text; ??????? /* First, read the length of the text message from the socket. If read returns zero, the client closed the connection. */ ??????? if (read (client_socket, &length, sizeof (length)) == 0) ??????????? return 0; ??????? /* Allocate a buffer to hold the text. */ ??????? text = (char*) malloc (length); ??????? /* Read the text itself, and print it. */ ??????? read (client_socket, text, length); ??????? printf (“%s\n”, text); ??????? /* Free the buffer. */ ??????? free (text); ??????? /* If the client sent the message “quit,” we’re all done. */ ??????? if (!strcmp (text, “quit”)) ??????????? return 1; ??? } } int main (int argc, char* const argv[]) { ??? const char* const socket_name = argv[1]; ??? int socket_fd; ??? struct sockaddr_un name; ??? int client_sent_quit_message; ??? /* Create the socket. */ ??? socket_fd = socket (PF_LOCAL, SOCK_STREAM, 0); ??? /* Indicate that this is a server. */ ??? name.sun_family = AF_LOCAL; ??? strcpy (name.sun_path, socket_name); ??? bind (socket_fd, &name, SUN_LEN (&name)); ??? /* Listen for connections. */ ??? listen (socket_fd, 5); ??? /* Repeatedly accept connections, spinning off one server() to deal with each client. Continue until a client sends a “quit” message. */ ??? do { ??????? struct sockaddr_un client_name; ??????? socklen_t client_name_len; ??????? int client_socket_fd; ??????? /* Accept a connection. */ ??????? client_socket_fd = accept (socket_fd, &client_name, &client_name_len); ??????? /* Handle the connection. */ ??????? client_sent_quit_message = server (client_socket_fd); ??????? /* Close our end of the connection. */ ??????? close (client_socket_fd); ??? } while (!client_sent_quit_message); ??? /* Remove the socket file. */ ??? close (socket_fd); ??? unlink (socket_name); ??? return 0; } (socket-client.c) Local Namespace Socket Client #include <stdio.h> #include <string.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> /* Write TEXT to the socket given by file descriptor SOCKET_FD. */ void write_text (int socket_fd, const char* text) { ??? /* Write the number of bytes in the string, including NUL-termination. */ ??? int length = strlen (text) + 1; ??? write (socket_fd, &length, sizeof (length)); ??? /* Write the string. */ ??? write (socket_fd, text, length); } int main (int argc, char* const argv[]) { ??? const char* const socket_name = argv[1]; ??? const char* const message = argv[2]; ??? int socket_fd; ??? struct sockaddr_un name; ??? /* Create the socket. */ ??? socket_fd = socket (PF_LOCAL, SOCK_STREAM, 0); ??? /* Store the server’s name in the socket address. */ ??? name.sun_family = AF_LOCAL; ??? strcpy (name.sun_path, socket_name); ??? /* Connect the socket. */ ??? connect (socket_fd, &name, SUN_LEN (&name)); ??? /* Write the text on the command line to the socket. */ ??? write_text (socket_fd, message); ??? close (socket_fd); ??? return 0; } | 
?
5.2、互聯(lián)網(wǎng)套接字
| (socket-inet.c) Read from a WWW Server #include <stdlib.h> #include <stdio.h> #include <netinet/in.h> #include <netdb.h> #include <sys/socket.h> #include <unistd.h> #include <string.h> /* Print the contents of the home page for the server’s socket. Return an indication of success. */ void get_home_page (int socket_fd) { ??? char buffer[10000]; ??? ssize_t number_characters_read; ??? /* Send the HTTP GET command for the home page. */ ??? sprintf (buffer, “GET /\n”); ??? write (socket_fd, buffer, strlen (buffer)); ??? /* Read from the socket. The call to read may not ??? return all the data at one time, so keep trying until we run out. */ ??? while (1) { ??????? number_characters_read = read (socket_fd, buffer, 10000); ??????? if (number_characters_read == 0) ??????????? return; ??????? /* Write the data to standard output. */ ??????? fwrite (buffer, sizeof (char), number_characters_read, stdout); ??? } } int main (int argc, char* const argv[]) { ??? int socket_fd; ??? struct sockaddr_in name; ??? struct hostent* hostinfo; ??? /* Create the socket. */ ??? socket_fd = socket (PF_INET, SOCK_STREAM, 0); ??? /* Store the server’s name in the socket address. */ ??? name.sin_family = AF_INET; ??? /* Convert from strings to numbers. */ ??? hostinfo = gethostbyname (argv[1]); ??? if (hostinfo == NULL) ??????? return 1; ??? else ??????? name.sin_addr = *((struct in_addr *) hostinfo->h_addr); ??? /* Web servers use port 80. */ ??? name.sin_port = htons (80); ??? /* Connect to the Web server */ ??? if (connect (socket_fd, &name, sizeof (struct sockaddr_in)) == -1) { ??????? perror (“connect”); ??????? return 1; ??? } ??? /* Retrieve the server’s home page. */ ??? get_home_page (socket_fd); ??? return 0; } | 
總結(jié)
以上是生活随笔為你收集整理的高级Linux程序设计第五章:进程间通信的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
 
                            
                        - 上一篇: bat脚本实现微信多开
- 下一篇: Linux_日志管理介绍(一)
