1.简介

  socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。

  UNIX Domain Socket是全双工的,API接口语义丰富,相比其它IPC机制有明显的优越性,目前已成为使用最广泛的IPC机制,比如X Window服务器和GUI程序之间就是通过UNIXDomain Socket通讯的

2.使用介绍

  使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符,address family指定为AF_UNIX,type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。

  UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示,网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。

3.与网络套接字对比

  对比网络套接字地址结构和本地套接字地址结构:

  struct sockaddr_in {

  __kernel_sa_family_t sin_family;                             /* Address family */      地址结构类型

  __be16 sin_port;                                                 /* Port number */             端口号

  struct in_addr sin_addr;                                               /* Internet address */     IP地址

  };

  struct sockaddr_un {

  __kernel_sa_family_t sun_family;                  /* AF_UNIX */                    地址结构类型

  char sun_path[UNIX_PATH_MAX];                 /* pathname */                 socket文件名(含路径)

  };

4.代码实现案列

文件1:wrap.h自己封装的出错处理函数头文件

 #ifndef __WRAP_H_
#define __WRAP_H_ void perr_exit(const char* s);
int Accept(int fd,struct sockaddr* sa,socklen_t* salenptr);
int Bind(int fd,const struct sockaddr* sa,socklen_t salen);
int Connect(int fd,const struct sockaddr* sa,socklen_t salen);
int Listen(int fd,int backlog);
int Socket(int family,int type,int protocol);
ssize_t Read(int fd,void* ptr,size_t nbytes);
ssize_t Write(int fd,const void* ptr,size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd,void* vptr,size_t n);
ssize_t Writen(int fd,const void* vptr,size_t n);
ssize_t my_read(int fd,char* ptr);
ssize_t Readline(int fd,void* vptr,size_t maxlen); #endif

文件2:wrap.c自己封装的出错处理函数实现

 #include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<sys/socket.h> void perr_exit(const char* s)
{
perror(s);
exit(-);
} int Accept(int fd,struct sockaddr* sa,socklen_t* salenptr)
{
int n;
again:
if((n = accept(fd,sa,salenptr))<)
{
if((errno == ECONNABORTED)||(errno == EINTR))
{
goto again;
}
else
{
perr_exit("accept error");
}
}
return n;
} int Bind(int fd,const struct sockaddr* sa,socklen_t salen)
{
int n;
if((n = bind(fd,sa,salen))<)
{
perr_exit("bind error");
}
return n;
} int Connect(int fd,const struct sockaddr* sa,socklen_t salen)
{
int n;
n = connect(fd,sa,salen);
if(n<)
{
perr_exit("connect error");
}
return n;
} int Listen(int fd,int backlog)
{
int n;
if((n = listen(fd,backlog))<)
{
perr_exit("listen error");
}
return n;
} int Socket(int family,int type,int protocol)
{
int n;
if((n = socket(family,type,protocol))<)
{
perr_exit("socket error");
}
return n;
} ssize_t Read(int fd,void* ptr,size_t nbytes)
{
ssize_t n;
again:
if((n = read(fd,ptr,nbytes)) == -)
{
if(errno == EINTR)
{
goto again;
}
else
{
return -;
}
}
return n;
} ssize_t Write(int fd,const void* ptr,size_t nbytes)
{
ssize_t n;
again:
if((n = write(fd,ptr,nbytes)) == -)
{
if(errno == EINTR)
{
goto again;
}
else
{
return -;
}
}
return n;
} int Close(int fd)
{
int n;
if((n = close(fd)) == -)
{
perr_exit("close error");
}
return n;
} ssize_t Readn(int fd,void* vptr,size_t n)
{
size_t nleft;
ssize_t nread;
char *ptr; ptr = vptr;
nleft = n; while(nleft > )
{
if((nread = read(fd,ptr,nleft))<)
{
if(errno == EINTR)
{
nread = ;
}
else
{
return -;
}
}
else if(nread == )
{
break;
}
nleft -= nread;
ptr += nread;
}
return n-nleft;
} ssize_t Writen(int fd,const void* vptr,size_t n)
{
size_t nleft;
ssize_t nwritten;
const char* ptr; ptr = vptr;
nleft = n;
while(nleft>)
{
if((nwritten = write(fd,ptr,nleft))<=)
{
if(nwritten < && errno == EINTR)
{
nwritten = ;
}
else
{
return -;
}
nleft -= nwritten;
ptr += nwritten;
}
}
return n;
} ssize_t my_read(int fd,char* ptr)
{
static int read_cnt;
static char *read_ptr;
static char read_buf[]; if (read_cnt <= )
{
again:
if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < )
{
if (errno == EINTR)
goto again;
return -;
} else if (read_cnt == )
return ;
read_ptr = read_buf;
}
read_cnt--;
*ptr = *read_ptr++; return ;
} ssize_t Readline(int fd,void* vptr,size_t maxlen)
{
ssize_t n, rc;
char c, *ptr;
ptr = vptr; for (n = ; n < maxlen; n++)
{
if ((rc = my_read(fd, &c)) == )
{
*ptr++ = c;
if (c == '\n')
break;
} else if (rc == )
{
*ptr = ;
return n-;
} else
return -;
}
*ptr = ; return n;
}

文件3:服务端程序server.c

 #include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include<sys/un.h>
#include<stdlib.h>
#include<stddef.h>
#include "wrap.h"
#define SERV_ADDR "serv.socket"
#define SERV_PORT 6666 int main(void)
{
int lfd, cfd;
int len, i;
char buf[BUFSIZ]; struct sockaddr_un serv_addr, clie_addr;
socklen_t clie_addr_len; lfd = Socket(AF_UNIX, SOCK_STREAM, ); unlink(SERV_ADDR);
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
len=offsetof(struct sockaddr_un,sun_path)+strlen(SERV_ADDR);
strcpy(serv_addr.sun_path,SERV_ADDR); Bind(lfd, (struct sockaddr *)&serv_addr, len); Listen(lfd, ); printf("wait for client connect ...\n"); clie_addr_len = sizeof(clie_addr_len); cfd = Accept(lfd, (struct sockaddr *)&clie_addr, &clie_addr_len); while () { len = Read(cfd, buf, sizeof(buf));
Write(STDOUT_FILENO, buf, len); for (i = ; i < len; i++)
buf[i] = toupper(buf[i]);
Write(cfd, buf, len);
} Close(lfd);
Close(cfd); return ;
}

文件4:客户端程序client.c

 #include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stddef.h>
#include <sys/un.h>
#include <ctype.h>
#include <sys/types.h>
#include "wrap.h"
#define CLIE_ADDR "clie.socket"
#define SERV_ADDR "serv.socket"
#define SERV_PORT 6666 int main(void)
{
int lfd, len,n;
struct sockaddr_un serv_addr, clie_addr;
char buf[BUFSIZ]; lfd = Socket(AF_UNIX, SOCK_STREAM, ); bzero(&clie_addr, sizeof(clie_addr));
clie_addr.sun_family = AF_UNIX;
strcpy(clie_addr.sun_path,CLIE_ADDR);
len=offsetof(struct sockaddr_un,sun_path)+strlen(CLIE_ADDR);
unlink(CLIE_ADDR);
Bind(lfd,(struct sockaddr*)&clie_addr,len); bzero(&serv_addr,sizeof(serv_addr));
serv_addr.sun_family=AF_UNIX;
strcpy(serv_addr.sun_path,SERV_ADDR);
len=offsetof(struct sockaddr_un,sun_path)+strlen(SERV_ADDR); Connect(lfd, (struct sockaddr *)&serv_addr, len); while () {
fgets(buf, sizeof(buf), stdin);
int r = Write(lfd, buf, strlen(buf));
printf("Write r ======== %d\n", r);
n = Read(lfd, buf, sizeof(buf));
printf("Read len ========= %d\n", n);
Write(STDOUT_FILENO, buf, n);
} Close(lfd); return ;
}

文件5:makefile编译文件

 src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src)) all:server client
server:server.o wrap.o
gcc server.o wrap.o -o server -Wall
client:client.o wrap.o
gcc client.o wrap.o -o client -Wall
%.o:%.c
gcc -c $< -Wall
.PHONY:clean all
clean:
-rm -rf server client $(obj)

5.编译以及运行效果

(1)执行make编译后如下图所示文件

(2)先执行./server程序,再执行./client程序

(3)在客户端输入hello world,会提示输入读写了多少字节,并且将服务端大写转小写写回到客户端屏幕上

(4)程序执行完成后会在当前目录下观察到有两个套接字文件:clie.socket和serv.socket

socket IPC(本地套接字 domain)的更多相关文章

  1. 【转】PHP实现系统编程(四)--- 本地套接字(Unix Domain Socket)

    原文:http://blog.csdn.net/zhang197093/article/details/78143687?locationNum=6&fps=1 --------------- ...

  2. 本地套接字-本地socket

    本地套接字简单应用场景 一 #服务端--简单 import socket import os a='sock_file' if os.path.exists(a): os.remove(a) s=so ...

  3. (十三) [终篇] 一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  4. Unix 环境高级编程 (APUE) 之 网络 IPC:套接字

    一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字 . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级 ...

  5. IPC——数据报套接字通信

    Linux进程间通信——使用数据报套接字 前一篇文章,Linux进程间通信——使用流套接字介绍了一些有关socket(套接字)的一些基本内容,并讲解了流套接字的使用,这篇文章将会给大家讲讲,数据报套接 ...

  6. IPC——流套接字通信

    Linux进程间通信——使用流套接字 前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进 ...

  7. 网络IPC:套接字之套接字描述符

    套接字是通信端点的抽象.与应用程序要使用文件描述符访问文件一样,访问套接字也需要套接字描述符.套接字描述符在UNIX系统是用文件描述符实现的.事实上,许多处理文件描述符的函数(如read和write) ...

  8. UNIX环境高级编程 第16章 网络IPC:套接字

    上一章(15章)中介绍了UNIX系统所提供的多种经典进程间通信机制(IPC):管道PIPE.命名管道FIFO.消息队列Message Queue.信号量Semaphore.共享内存Shared Mem ...

  9. Linux 进程间通信(二)(网络IPC:套接字)

    socket描述符 套接字是通信端点的抽象,创建一个套接字使用如下函数: #include <sys/socket.h> int socket(int domain, int type, ...

随机推荐

  1. Docker入门与应用系列(八)Docker图形界面管理之Shipyard

    Shipyard基于Docker API实现的容器图形管理系统,支持container.images.engine.cluster等功能,可满足我们基本的容器部署需求可堆栈的Docker管理基于Doc ...

  2. 自己搭建v,p,n过程

    安装dockeryum install -y docker把docker设置为服务systemctl enable docker.service启动dockersystemctl start dock ...

  3. Java每日一题

    1.(单选题)What will be printed when you execute the following code? class C { C() { System.out.print(&q ...

  4. 52、图片缩放库 PhotoView

    PhotoView的简介: 这是一个图片查看库,实现图片浏览功能,支持pinch(捏合)手势或者点击放大缩小.支持在ViewPager中翻页浏览图片. PhotoView 是一款扩展自Android ...

  5. Vue与React的异同 -生命周期

    vue的生命周期 创建前 beforeCreate 创建   create 挂载前 beforeMount 挂载 mounted 更新前 beforeUpdate 更新 updated 销毁前 bef ...

  6. ZOJ 2676 Network Wars[01分数规划]

    ZOJ Problem Set - 2676 Network Wars Time Limit: 5 Seconds      Memory Limit: 32768 KB      Special J ...

  7. 延迟任务和循环任务ScheduledExecutorService

    public class ScheduledThreadPool { public static ScheduledExecutorService scheduledThreadPool = Exec ...

  8. css3动画效果:1基础

    css动画分两种:过渡效果transition .关键帧动画keyframes 一.过渡效果transition 需触发一个事件(如hover.click)时,才改变其css属性. 过渡效果通常在用户 ...

  9. 并发编程7 管道&事件&信号量&进程池(同步和异步方法)

    1,管道 2.事件 3.信号量 4.进程池的介绍&&进程池的map方法&&进程池和多进程的对比 5.进程池的同步方法和异步方法 6.重新解释同步方法和异步方法 7.回调 ...

  10. powershell Start-Sleep

    秒: Start-Sleep –s 10 ,毫秒) Start-Sleep –m 10000 语法 Start-Sleep [-seconds] <int> [<CommonPara ...