一. 進程簡述:
進程是操作系統(tǒng)的概念,每當我們執(zhí)行一個程序時,對于操作系統(tǒng)來講就創(chuàng)建了一個進程,在這個過程中,伴隨著資源的分配和釋放??梢哉J為進程是一個程序的一次執(zhí)行過程。
1)Linux下進程結構
Linux下一個進程在內存里有三部分的數據,就是"代碼段"、"堆棧段"和"數據段"。其實學過匯編語言的人一定知道,一般的CPU都有上述三種段寄存器,以方便操作系統(tǒng)的運行。
這三個部分也是構成一個完整的執(zhí)行序列的必要的部分。所以不同的進程間,由于linux系統(tǒng)虛擬內存地址的管理,這三個段也是獨立存在的,所以進程間是不能相互訪問數據的,需要通過系統(tǒng)提供的特殊方法來進行相互通信。
2)Linux下進程通信的方法:
進程用戶空間是相互獨立的,一般而言是不能相互訪問的。但很多情況下進程間需要互相通信,來完成系統(tǒng)的某項功能。進程通過與內核及其它進程之間的互相通信來協(xié)調它們的行為。
比較常用的IPC通信方法有:
管道(有名和無名)、信號、信號量、共享內存、消息隊列和套接字socket通信。
	
3)進程通信使用場景:
(1)數據傳輸:進程間數據傳輸;
(2)通知事件:一個進程向另一個或一組進程發(fā)送消息,通知某個事件的發(fā)生(如子進程終止時需通知父進程);
(3)資源共享:多個進程共享資源,需要內核提供同步互斥機制;
(4)進程控制:某進程需要控制另一個進程的執(zhí)行(如Debug進程),此時控制進程需要攔截另一個進程的所有陷入、異常、狀態(tài)等。
二. 進程通信的方法:
1. 有名管道和無名管道
a. 無名管道(父子進程、兄弟進程間通信):
---特點:
(1) 半雙工。數據同一時刻只能單向傳輸;
(2) 數據從管道一端寫入,另一端讀出;
(3) 寫入管道的數據遵循先進先出;
(4) 管道非普通文件,不屬于某個文件系統(tǒng),只存在于內存;
(5) 無名管道只能在具有公共祖先的進程(父子進程、兄弟進程等)之間使用。
---操作步驟:
(1)創(chuàng)建: pipe函數用來創(chuàng)建無名管道
(3)關閉操作端口: close
例子程序:
#include 
#include 
#include 
#include 
#include 
#include 
int main(void)
{
char buf[32] = {0};
pid_t pid;
//  數量為 2 個:一個讀端, 一個寫端,
int fd[2] = {-1};
// 創(chuàng)建無名管道
pipe(fd);
printf("fd[0] is %d
", fd[0]);
printf("fd[2] is %d
", fd[1]);
// 創(chuàng)建進程
pid = fork();
if (pid < 0)
{
   printf("error
");
} 
if (pid > 0)
{
int status;
close(fd[0]);
write(fd[1], "hello", 5);
close(fd[1]);
wait(&status);
exit(0);
} 
if (pid == 0)
{
   close(fd[1]);
   read(fd[0], buf, 32);
   printf("buf is %s
", buf);
   close(fd[0]);
   exit(0);
}
return 0;
}  
b. 有名管道(允許無親緣關系進程間的通信)。
----特點:
(1) 它可以使互不相關的兩個進程實現(xiàn)彼此通信
(2) 該管道可以通過路徑名來指出,并且在文件系統(tǒng)中是可見的。在建立管道之后,兩個進程就可以把它當作普通文件進行讀寫,使用非常方便。
(3) FIFO嚴格遵循先進先出原則,對管道及FIFO的讀總是從開始處返回數據,對它們的寫則把數據添加到末尾。有名管道不支持如Iseek()等文件的定位操作。
---操作步驟:
(1) 創(chuàng)建有名管道文件: mkfifo即是命令也是函數;mknod也可以創(chuàng)建管道文件;
(2) 打開有名管道: open;
(3) 讀/寫: read/write
(4) 關閉: close
例子程序:
(1)named_pipe_write.c:
#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(int argc, char *argv[])
{
int ret;
char buf[32] = {0};
int fd;
if (argc < 2)
{
   printf("Usage:%s  
", argv[0]);
   return -1;
} 
if (access(argv[1], F_OK) == -1)
{
///創(chuàng)建有名管道文件
ret = mkfifo(argv[1], 0666);
if (ret == -1)
{
 printf("mkfifo is error 
");
 return -2;
} 
printf("mkfifo is ok 
");
 }
///打開有名管道文件
 fd = open(argv[1], O_WRONLY);
 while (1)
 {
sleep(1);
write(fd, "hello", 5);
 } 
 close(fd);
 return 0;
}
 
(2) named_pipe_read.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(int argc, char *argv[])
{
char buf[32] = {0};
int fd;
if (argc < 2)
{
 printf("Usage:%s  
", argv[0]);
 return -1;
} 
///打開有名管道,write已經創(chuàng)建的文件;
fd = open(argv[1], O_RDONLY);
while (1)
{
 sleep(1);
 read(fd, buf, 32);
 printf("buf is %s
", buf);
 memset(buf, 0, sizeof(buf));
} 
close(fd);
return 0;
}
2.信號量
1) 概念和原理:
信號量是一種計數器,用于控制對共享資源的訪問。每次進程訪問共享資源時,都要先獲取一個信號量,如果信號量的值大于0,
則進程可以繼續(xù)訪問,否則進程需要等待。訪問完成后,進程會釋放信號量,使其值加1,以便其他進程訪問;
2) 相關函數:
linux系統(tǒng)提供如下函數來對信號量值進行操作的,包括的頭文件為sys/sem.h。
--semget函數:創(chuàng)建一個新信號量或者獲取一個已有的信號量的鍵
--semop函數: 對信號量進行改變,做p或者v操作
--semctl函數:用來直接控制信號量信息
--刪除信號量:ipcrm -s id
3)例子程序:
---增加信號量的值例子(sempore_add.c )://=============================sempore_add.c==========================
#include 
#include 
#include 
#include 
#define KEY 1234
union semun {
int val;
struct semid_ds *buf;
ushort *array;
};
int main()
{
int semid = semget(KEY, 1, IPC_CREAT | 0666);
if (semid < 0) {
perror("semget error");
return 1;
}
union semun arg;
arg.val = 1;
if (semctl(semid, 0, SETVAL, arg) < 0) {
perror("semctl error");
return 1;
}
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1;
buf.sem_flg = SEM_UNDO;
if (semop(semid, &buf, 1) < 0) {
perror("semop error");
return 1;
}
printf("Semaphore value: %d
", semctl(semid, 0, GETVAL, arg));
return 0;
}
---減少信號量的值例子(sempore_sub.c):
//=============================sempore_sub.c==========================
#include 
#include 
#include 
#include 
#define KEY 1234
union semun {
int val;
struct semid_ds *buf;
ushort *array;
};
int main()
{
int semid = semget(KEY, 1, IPC_CREAT | 0666);
if (semid < 0) {
perror("semget error");
return 1;
}
union semun arg;
arg.val = 1;
if (semctl(semid, 0, SETVAL, arg) < 0) {
perror("semctl error");
return 1;
}
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;
buf.sem_flg = SEM_UNDO;
if (semop(semid, &buf, 1) < 0) {
perror("semop error");
return 1;
}
printf("Semaphore value: %d
", semctl(semid, 0, GETVAL, arg));
////銷毀信號量  
if (semctl(semid, 0, IPC_RMID, 0) < 0) {
perror("semctl error");
return 1;
}
printf("Semaphore destroyed
");
return 0;
} 
3.信號
(1)信號概念和原理:
信號是一種異步通信方式,當進程接收到一個信號時,會打斷當前的執(zhí)行,轉而執(zhí)行與該信號相關聯(lián)的信號處理函數。 比較類似軟中斷。但信號和中斷有所不同,中斷的響應和處理都發(fā)生在內核空間,而信號的響應發(fā)生在內核空間, 信號處理程序的執(zhí)行卻發(fā)生在用戶空間。
Linux提供了許多信號,如SIGINT、SIGTERM、SIGKILL等,可以在linux系統(tǒng) Shell 中查看所有信號和對應的編號:kill -l
(2)主要函數:
a. void (*signal(int sig,void (*func)(int)))(int);
說明:綁定收到某個信號后 的回調函數.第一個參數為信號,第二個參數為對此信號掛接用戶自己的處理函數指針。 返回值為以前信號處理程序的指針。例子:int ret = signal(SIGSTOP, sig_handle);
b. int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
說明:由于 signal 不夠健壯,推薦使用 sigaction 函數,sigaction 函數重新實現(xiàn)了 signal 函數
c. int kill(pid_t pid,int sig);
說明:kill函數向進程號為pid的進程發(fā)送信號,信號值為sig。當pid為0時,向當前系統(tǒng)的所有進程發(fā)送信號sig。
kill的pid參數有四種情況:
---pid>0, 則發(fā)送信號sig給進程號為pid的進程
---pid=0,則發(fā)送信號sig給當前進程所屬組中的所有進程
---pid=-1,則發(fā)送信號sig給除1號進程與當前進程外的所有進程
---pid<-1,則發(fā)送信號sig給屬于進程組pid的所有進程
例子:結束父進程 kill(getppid(), SIGKILL);
d. int raise(int sig);
說明: 向當前進程中自舉一個信號sig, 即向當前進程發(fā)送信號。相當于 kill(getpid(),sig);
e. unsigned int alarm(unsigned int seconds);
說明: 用來設置信號SIGALRM在經過參數seconds指定的秒數后傳送給目前的進程. 如果參數seconds為0,則之前設置的鬧鐘會被取消,并將剩下的時間返回
f. int sigqueue(pid_t pid, int sig, const union sigval value);
說明:用于向指定的進程發(fā)送特定的信號,并且可以傳遞一個額外的數據值。它提供了比 kill 函數更豐富的功能,可以用于進程間的高級通信。
(3)例子程序:
-----------------signal_receiver.c ------------------------------
#include 
#include 
#include 
#include 
#include 
#include 
void signal_Handle(int sig, siginfo_t* info, void* ucontext)
{
printf("handler : sig = %d
", sig);
printf("handler : info->si_signo = %d
", info->si_signo);
printf("handler : info->si_code = %d
", info->si_code);
printf("handler : info->si_pid = %d
", info->si_pid);
printf("handler : info->si_value = %d
", info->si_value.sival_int);
}
int main(int argc, char** argv)
{
printf("pid :%d
", getpid());
struct sigaction act = {0};
act.sa_sigaction = signal_Handle;
act.sa_flags = SA_RESTART | SA_SIGINFO;
/* 添加信號屏蔽字 */
/* 下面信號在信號處理程序執(zhí)行時會被暫時阻塞 */
sigaddset(&act.sa_mask, 40);
sigaddset(&act.sa_mask, SIGINT);
/* 設置信號的處理行為,設置后40和SIGINT信號將由act里面的信號處理函數處理 */
sigaction(40, &act, NULL);
sigaction(SIGINT, &act, NULL);
while(1)
{
sleep(1);
}
return 0;
}
-----------------signal_sender.c ------------------------------
#include 
#include 
#include 
#include 
#include 
int main(int argc, char** argv)
{
pid_t pid = atoi(argv[1]);
union sigval sv = {123456};
//向指定pid發(fā)送信號;
sigqueue(pid, 40, sv);
raise(SIGINT); 
return 0;
}
4.消息隊列
(1)概念和原理:
消息隊列是一種進程間通信的方式,允許一個進程向另一個進程發(fā)送消息。它是一種異步通信方式,發(fā)送方發(fā)送消息后即可繼續(xù)執(zhí)行,不必等待接收方的響應。
原理如下圖所示:
	
(2)特點:
---消息隊列是消息的鏈表,存放于內存中,內核維護消息隊列;
---消息隊列中的消息是有類型和格式的;
---消息隊列可實現(xiàn)消息隨機查詢,不一定要遵循先進先出的順序,而是每個進程可以按照自定義的類型進行讀??;
---與管道相同,讀出數據后,消息隊列對應數據會被刪除;
---每個管道都有消息隊列標識符,在整個系統(tǒng)中是唯一的;
---消息隊列允許一個或者多個進程向它寫入或者讀取數據;
---內核重啟或者人為刪除才會刪除消息隊列,否則會一直存在與系統(tǒng)中
(3) 相關函數:
a. key_t ftok(const char *pathname, int proj_id);
說明:獲取系統(tǒng)唯一Key值(IPC鍵值),系統(tǒng)中可能會存在許多的消息隊列,通過Key這個系統(tǒng)唯一值,可以選擇想要進入的消息隊列;
b. int msgget(key_t key, int msgflg);
說明:創(chuàng)建或者打開一個新的消息隊列。即使進程不同,但是如果key值是相同的,那么也可以進入相同的消息隊列,返回相同的消息隊列標識符,
c. 查看消息隊列的一些Linux命令:
ipcs -q : 查看當前進程間通信之消息隊列
ipcrm -q 隊列號: 刪除指定的消息隊列;
d. int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
說明: 將新消息添加到消息隊列;
e. ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
說明: 從指定的消息隊列標識符中接受信息,同時一旦接受成功,從消息隊列中刪除該信息。
f. int msgctl(int msqid, int cmd, struct msqid_ds *buf);
說明:對消息隊列進行修改,修改屬性或者刪除消息隊列等
	
(3)例子程序:
-----------------message_sender.c ------------------------------
#include
#include
#include
#include
#include
//定義消息
struct mess
{
long type;
char data[128];
};
int main()
{
key_t  key;
///創(chuàng)建生成唯一的key; 
if ((key = ftok("/home/tmp", 'a')) == -1) {
perror("ftok");
exit(1);
} 
int msgid=msgget((key_t)key,IPC_CREAT|0600); 
if(msgid==-1)
{
exit(0);
}
struct mess dt;
dt.type=1;
strcpy(dt.data,"hello1");
//1號消息內容hello1
msgsnd(msgid,(void*)&dt,128,0);//標志位0 
}
 
-----------------message_reader.c ------------------------------
#include
#include
#include
#include
 
struct mess
{
long type;
char data[128];
};
int main()
{
int msgid=msgget((key_t)1235,IPC_CREAT|0600);
if(msgid==-1)
{
exit(0);
}
struct mess dt;
msgrcv(msgid,(void*)&dt,128,1,0);
printf("%s",dt.data);
///刪除隊列
if (msgctl(msqid, IPC_RMID, NULL) == -1) {
perror("msgctl");
exit(1);
}
}
5.共享內存
(1)概念:
共享內存是一種高效的IPC機制,是最快的進程間通信方式,很多追求效率的程序之間進行通信的時候都會選擇它;它允許多個進程共享同一個物理內存區(qū)域,從而避免了數據拷貝和進程切換的開銷。
原理如下圖所示:
	
(2)共享內存的建立與釋放:
---共享內存的建立大致包括以下兩個過程:
a.在物理內存當中申請共享內存空間;
b.將申請到的共享內存掛接到地址空間,即建立映射關系;
---共享內存的釋放大致包括以下兩個過程:
a. 將共享內存與地址空間去關聯(lián),即取消映射關系。
b. 釋放共享內存空間,即將物理內存歸還給系統(tǒng)。
(3)相關函數:
a.key_t ftok(const char *pathname, int proj_id);
說明:這個返回的key值可以傳給共享內存參數,作為struct ipc_perm中唯一標識共享內存的key;
b. int shmget(key_t key, size_t size, int shmflg);
說明:共享內存的創(chuàng)建;
c. void *shmat(int shmid, const void *shmaddr, int shmflg)
說明:將共享內存連接到進程地址空間,shmat函數的第三個參數shmflg有以下三個選項:
SHM_RDONLY: 關聯(lián)共享內存后只進行讀取操作
SHM_RND:若shmaddr不為NULL,則關聯(lián)地址自動向下調整為SHMLBA的整數倍。
0: 默認為讀寫權限
d. int shmctl(int shmid, int cmd, struct shmid_ds *buf);
說明:控制共享內存,cmd如下:
IPC_STAT: 獲取共享內存的當前關聯(lián)值,此時參數buf作為輸出型參數
IPC_SET: 在進程有足夠權限的前提下,將共享內存的當前關聯(lián)值設置為buf所指的數據結構中的值
IPC_RMID: 刪除共享內存段;
e. int shmdt(const void *shmaddr)
說明:取消共享內存與進程地址空間之間的關聯(lián)
(3)內存共存相關的系統(tǒng)命令:
---查看共享內存命令:ipcs -m
---刪除共享內存命令:ipcrm -m
(4)例子程序:共享內存數據讀;
  //shm_server.c
  -----------------shm_server.c ------------------------------
#include 
#include 
#include 
#include 
#include 
#include 
 
#define PATHNAME "/home/IPC/shm/server.c" //路徑名 
#define PROJ_ID 0x6666 //整數標識符
 
int main()
{
key_t key = ftok(PATHNAME, PROJ_ID); //獲取key值
if (key < 0){
perror("ftok");
return 1;
}
 
int shm = shmget(key, SIZE, IPC_CREAT | IPC_EXCL | 0666); //創(chuàng)建新的共享內存
if (shm < 0){
perror("shmget");
return 2;
}
printf("key: %x
", key); //打印key值
printf("shm: %d
", shm); //打印共享內存用戶層id
 
char* mem = shmat(shm, NULL, 0); //關聯(lián)共享內存
 
while (1)
{ 
//服務端不斷讀取共享內存當中的數據并輸出
while (1)
{
printf("client# %s
", mem);
sleep(1);
}
 
}
 
shmdt(mem); //共享內存去關聯(lián)
 
shmctl(shm, IPC_RMID, NULL); //釋放共享內存
return 0;
}
客戶端: 共享內存數據寫;
-----------------shm_client.c ------------------------------
#include 
#include 
#include 
#include 
#include 
#include 
 
#define PATHNAME "/home/IPC/shm/server.c" //路徑名 
#define PROJ_ID 0x6666 //整數標識符
 
int main()
{
key_t key = ftok(PATHNAME, PROJ_ID); //獲取與server進程相同的key值
if (key < 0){
perror("ftok");
return 1;
}
int shm = shmget(key, SIZE, IPC_CREAT); //獲取server進程創(chuàng)建的共享內存的用戶層id
if (shm < 0){
perror("shmget");
return 2;
}
 
printf("key: %x
", key); //打印key值
printf("shm: %d
", shm); //打印共享內存用戶層id
 
char* mem = shmat(shm, NULL, 0); //關聯(lián)共享內存
 
int i = 0;
while (1)
{
//客戶端不斷向共享內存寫入數據
int i = 0;
while (1)
{
mem[i] = 'A' + i;
i++;
mem[i] = '?';
sleep(1);
} 
}
 
shmdt(mem); //共享內存去關聯(lián)
return 0;
}
6.套接字
(1)概念和原理:
套接字是一種用于網絡通信的編程接口, 也是一種特殊的IPC通信機制,一般分為兩種角色:客戶端和服務器 ,既可以在本機不同進程間通信,也可以在跨網絡不同的多臺主機間通信,可以一對多。
流程如下圖:
	
(2)相關函數:
a. int tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
說明:創(chuàng)建Socket函數創(chuàng)建一個Socket對象,并指定通信協(xié)議和類型(流式或數據報式)。 IPPROTO_TCP表示TCP協(xié)議
b. int bind(int sock, struct sockaddr *addr, socklen_t addrlen); //Linux
說明:綁定地址,使用 bind 函數將 Socket 綁定到一個特定的IP地址和端口號上。
c. listen;
說明:設置監(jiān)聽,等待接收client端連接請求;
d. int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
說明:接受連接,對于流式 Socket,使用 accept 函數接受客戶端的連接請求,并返回一個新的Socket對象用于與客戶端進行通信。 對于數據報式Socket,可以省略此步驟。
e. int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen);
說明:連接指定IP和端口的服務器
f. ssize_t send(int sockfd, const void *buf, size_t len, int flags);
或ssize_t write(int fd, const void *buf, size_t nbytes);
說明:數據發(fā)送;
g. ssize_t recv(int sockfd, void *buf, size_t len, int flags);
或 ssize_t read(int fd, void *buf, size_t nbytes);
說明:數據接收;
h. int close(int fd) ;
說明:關閉連接,使用 close 函數關閉Socket連接。
(3)例子程序:
本地socket 通信 服務端程序:
----------------local_socket_server.c ------------------------------
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define QLEN 10
#define IPC_SOCKET_PATH "ipctest.socket"
int serv_listen(const char *name)
{
int fd, len, err, rval;
struct sockaddr_un un;
/* create a UNIX domain stream socket */
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
return(-1);
/* in case it already exists */
unlink(name); 
/* fill in socket address structure */
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
strcpy(un.sun_path, name);
len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
/* bind the name to the descriptor */
if (bind(fd, (struct sockaddr *)&un, len) < 0) {
rval = -2;
goto errout;
}
if (listen(fd, QLEN) < 0) { /* tell kernel we're a server */
rval = -3;
goto errout;
}
return(fd);
errout:
err = errno;
close(fd);
errno = err;
return(rval);
}
int serv_accept(int listenfd, uid_t *uidptr)
{
int clifd, len, err, rval;
time_t staletime;
struct sockaddr_un un;
struct stat statbuf;
len = sizeof(un);
if ((clifd = accept(listenfd, (struct sockaddr *)&un, &len)) < 0)
return(-1); /* often errno=EINTR, if signal caught */
/* obtain the client's uid from its calling address */
len -= offsetof(struct sockaddr_un, sun_path); /* len of pathname */
un.sun_path[len] = 0; /* null terminate */
if (stat(un.sun_path, &statbuf) < 0) {
rval = -2;
goto errout;
}
if (S_ISSOCK(statbuf.st_mode) == 0) {
rval = -3; /* not a socket */
goto errout;
}
if (uidptr != NULL)
*uidptr = statbuf.st_uid; /* return uid of caller */
/* we're done with pathname now */
unlink(un.sun_path); 
return(clifd);
errout:
err = errno;
close(clifd);
errno = err;
return(rval);
}
///////////////////////////main ////////////////////////////////
int main(void)
{
int lfd, cfd, n, i;
uid_t cuid;
char buf[1024];
lfd = serv_listen(IPC_SOCKET_PATH);
if (lfd < 0) {
switch (lfd) {
case -3:perror("listen"); break;
case -2:perror("bind"); break;
case -1:perror("socket"); break;
}
exit(-1);
}
cfd = serv_accept(lfd, &cuid);
if (cfd < 0) {
switch (cfd) {
case -3:perror("not a socket"); break;
case -2:perror("a bad filename"); break;
case -1:perror("accept"); break;
}
exit(-1);
}
while (1) 
{
n = read(cfd, buf, 1024);
if (n == -1) {
if (errno == EINTR)
break;
}
else if (n == 0) {
printf("the other side has been closed.
");
break;
}
////send back data to client
for (i = 0; i < n; i++)
{buf[i] = toupper(buf[i]);
write(cfd, buf, n);
}
}
close(cfd);
close(lfd);
return 0;
}
 
本地socket 通信 客戶端程序:
----------------local_socket_client.c ------------------------------
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define CLI_PATH "/var/tmp/" /* +5 for pid = 14 chars */
#define IPC_SOCKET_PATH "ipctest.socket"
/*
* Create a client endpoint and connect to a server.
* Returns fd if all OK, <0 on error.
*/
int cli_conn(const char *name)
{
int fd, len, err, rval;
struct sockaddr_un un;
/* create a UNIX domain stream socket */
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
return(-1);
/* fill socket address structure with our address */
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
sprintf(un.sun_path, "%s%05d", CLI_PATH, getpid());
len = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
/* in case it already exists */
unlink(un.sun_path); 
if (bind(fd, (struct sockaddr *)&un, len) < 0) {
rval = -2;
goto errout;
}
/* fill socket address structure with server's address */
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
strcpy(un.sun_path, name);
len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
if (connect(fd, (struct sockaddr *)&un, len) < 0) {
rval = -4;
goto errout;
}
return(fd);
errout:
err = errno;
close(fd);
errno = err;
return(rval);
}
///////////////////////////main ////////////////////////////////
int main(void)
{
int fd, n;
char buf[1024];
fd = cli_conn(IPC_SOCKET_PATH);
if (fd < 0) {
switch (fd) {
case -4:perror("connect"); break;
case -3:perror("listen"); break;
case -2:perror("bind"); break;
case -1:perror("socket"); break;
}
exit(-1);
}
while (fgets(buf, sizeof(buf), stdin) != NULL) {
write(fd, buf, strlen(buf));
n = read(fd, buf, sizeof(buf));
write(STDOUT_FILENO, buf, n);
}
close(fd);
return 0;
}
不同主機端的套接字IPC通信屬于網絡通信話題,這里就不再詳細論述了。
審核編輯:湯梓紅
- 
                                通信
                                +關注
關注
18文章
6275瀏覽量
139342 - 
                                Linux
                                +關注
關注
88文章
11586瀏覽量
217346 - 
                                操作系統(tǒng)
                                +關注
關注
37文章
7280瀏覽量
128264 - 
                                進程
                                +關注
關注
0文章
208瀏覽量
14473 
原文標題:6.套接字
文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
Linux系統(tǒng)下進程的幾種狀態(tài)介紹
    
          
        
        
Linux下進程通信的方法
                
 
    
    
           
            
            
                
            
評論