- 本次案例使用域套接字的字节流(SOCK_STREAM)通信方式
一、common.h与common.c文件
//common.h
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
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){
act.sa_flags |= SA_INTERRUPT;
}else{
act.sa_flags |= SA_RESTART;
}
if(sigaction(signo,&act,&oact)==-1)
return SIG_ERR;
return (oact.sa_handler);
}
二、服务端
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函数:)
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);
}
演示结果