• 本次案例使用域套接字的字节流(SOCK_STREAM)通信方式

一、common.h与common.c文件

//common.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <strings.h>
#include <signal.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>

#define UXIX_PATH "/home/dongshao/unix.str"
#define LISTEN_NUM 10
#define BUFF_SIZE 1024

typedef void Sigfunc(int);

int Socket(int domain,int type,int protocal);

void Bind(int sockfd,struct sockaddr* addr,int addrsize);

void Listen(int sockfd,int listennum);

int Accept(int sockfd,struct sockaddr* addr,socklen_t *addsize);

void Connect(int sockfd,struct sockaddr* addr,int addrsize);

void sig_chld(int signo);

Sigfunc* signal(int signo,Sigfunc* func);
//common.c
#include "common.h"

int Socket(int domain,int type,int protocal)
{
int sockFd;
if((sockFd=socket(domain,type,protocal))==-1){
perror("socket");
exit(EXIT_FAILURE);
}
return sockFd;
}

void Bind(int sockfd,struct sockaddr* addr,int addrsize)
{
if(bind(sockfd,addr,addrsize)==-1){
perror("bind");
exit(EXIT_FAILURE);
}
}

void Listen(int sockfd,int listennum)
{
if(listen(sockfd,listennum)==-1){
perror("bind");
exit(EXIT_FAILURE);
}
}

int Accept(int sockfd,struct sockaddr* addr,socklen_t *addsize)
{
int acceptFd;
struct sockaddr_un acceptAddr;
bzero(&acceptAddr,sizeof(acceptAddr));
acceptFd=accept(sockfd,(struct sockaddr*)&acceptAddr,addsize);

memcpy(addr,&acceptAddr,sizeof(acceptAddr));
return acceptFd;
}

void Connect(int sockfd,struct sockaddr* addr,int addrsize)
{
if(connect(sockfd,addr,addrsize)==-1){
perror("connect");
exit(EXIT_FAILURE);
}
}

void sig_chld(int signo)
{
pid_t pid;
int stat;

while((pid=waitpid(-1,&stat,WNOHANG))>0)
printf("child %d terminaled\n",pid);
return;
}

Sigfunc* signal(int signo,Sigfunc* func)
{
struct sigaction act,oact;
act.sa_handler=func;
sigemptyset(&act.sa_mask);
act.sa_flags=0;

if(signo==SIGALRM){
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
}else{
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART;
#endif
}
if(sigaction(signo,&act,&oact)==-1)
return SIG_ERR;
return (oact.sa_handler);
}

二、服务端

#include "common.h"

int main(int argc,char *argv[])
{
pid_t pid;
char buff[BUFF_SIZE];
int serFd,connFd;
socklen_t addrLen;
struct sockaddr_un serAddr;
struct sockaddr_un cliAddr;

serFd=Socket(AF_LOCAL,SOCK_STREAM,0);

unlink(UXIX_PATH); //绑定之前解除关联,放置UNIX_PATH所指文件已经存在

bzero(&serAddr,sizeof(serAddr));
serAddr.sun_family=AF_LOCAL;
strcpy(serAddr.sun_path,UXIX_PATH);

Bind(serFd, (struct sockaddr*)&serAddr,sizeof(serAddr));

Listen(serFd,LISTEN_NUM);

signal(SIGCLD,sig_chld); //子进程状态改变(终止或停止)时信号处理

addrLen=sizeof(cliAddr);
for(;;){
bzero(&cliAddr,sizeof(cliAddr));
if((connFd=Accept(serFd, (struct sockaddr *)&cliAddr,&addrLen))<0){
if(errno==EINTR)
continue;
else{
perror("accept");
continue;
}
}

fprintf(stdout,"get connect\n");

if((pid=fork())<0){ //fork失败
perror("fork");
exit(EXIT_FAILURE);
}else if(pid==0){ //子进程
close(serFd); //关闭父进程的fd,不再需要使用
while(1){
bzero(buff,sizeof(buff));
ssize_t _s=read(connFd,buff,sizeof(buff));
if(_s>0){
if(strncmp(buff,"quit",4)==0)
exit(0);
fprintf(stdout,"recv:%s\n",buff);
printf("Enter:");
fflush(stdout);
scanf("%s",buff);
if(strncmp(buff,"quit",4)==0){
fprintf(stdout,"quit\n");
break;
}
if(write(connFd,buff,strlen(buff))==-1)
exit(EXIT_FAILURE);
}
}
exit(0);
}
close(connFd);//父进程关闭子进程连接的fd
}
}

三、客户端

  • 客户端调用tmpnam函数产生一个唯一的文件名(tmpnam函数:)
#include "common.h"

int main(int argc,char *argv[])
{
int cliFd;
char buff[BUFF_SIZE];
struct sockaddr_un cliAddr;
struct sockaddr_un serAddr;
cliFd=Socket(AF_LOCAL,SOCK_STREAM,0);

bzero(&cliAddr,sizeof(cliAddr));
bzero(&serAddr,sizeof(serAddr));

//绑定客户端的地址
cliAddr.sun_family=AF_LOCAL;
strcpy(cliAddr.sun_path,tmpnam(NULL)); //此处我们使用tmpnam函数给客户端绑定一个唯一的地址
serAddr.sun_family=AF_LOCAL;
strcpy(serAddr.sun_path,UXIX_PATH);

Bind(cliFd, (struct sockaddr *)&cliAddr,sizeof(cliAddr));

Connect(cliFd, (struct sockaddr *)&serAddr,sizeof(serAddr));

fprintf(stdout,"connect success\n");
for(;;){
bzero(buff,sizeof(buff));
printf("Enter:");
fflush(stdout);
ssize_t _s=read(0,buff,sizeof(buff));
if(_s>0){
if(strncmp(buff,"quit",4)==0){
if(write(cliFd,buff,strlen(buff))==-1){
perror("write");
exit(EXIT_FAILURE);
}
goto end;
}
if(write(cliFd,buff,strlen(buff))==-1){
perror("write");
exit(EXIT_FAILURE);
}
_s=read(cliFd,buff,sizeof(buff));
if(strncmp(buff,"quit",4)==0)
goto end;
if(_s>0){
fprintf(stdout,"recv:%s\n",buff);
}
}
}
end:
close(cliFd);
fprintf(stdout,"quit\n");
exit(0);
}


演示结果

 APUE编程:136---进程间通信(命名域套接字的服务端/客户端通信案例)_#include