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. apache的ab命令做压力测试

    1. 最基本的关心两个选项 -c -n 例: ./ab -c 100 -n 10000 http://127.0.0.1/index.php -c 100 即:每次并发100个-n 10000 即: ...

  2. 面试题思考: 什么是事务(ACID)?

    事务(Transaction)是由一系列对系统中数据进行访问与更新的操作所组成的一个程序 执行逻辑单元(Unit). 狭义上的事务特指数据库事务.一方面,当多个应用程序并发访问数据库时,事务可以在这些 ...

  3. GCD介绍(四): 完结

    转自http://www.dreamingwish.com/dream-2012/gcd-four-the-the-odds-and-ends.html Dispatch Queue挂起 dispat ...

  4. IOS控件:计算文字长度(UITextField,UILabel对象 和 IBAction)

    #import <UIKit/UIKit.h> // UIViewController类为程序提供了基本的视图管理模块 @interface NavControllerViewContro ...

  5. Faster R-CNN利用新的网络结构来训练

    前言 最近利用Faster R-CNN训练数据,使用ZF模型,效果无法有效提高.就想尝试对ZF的网络结构进行改造,记录下具体操作. 一.更改网络,训练初始化模型 这里为了方便,我们假设更换的网络名为L ...

  6. c语言加密算法头文件下载(base64、md5、sha1)

    1.base64 网上有一份开头就是 // Encoding lookup table char base64encode_lut[] = {  的base64.h, 在loadrunner中加密有b ...

  7. [LintCode] 第k大元素

    基于快速排序: class Solution { public: /* * param k : description of k * param nums : description of array ...

  8. Oracle 数据库的组成(instance+database)

    Oracle服务器是一种对象关系数据库管理系统,它为信息管理提供开放.综合.集成的方法. Oracle服务器中有多种进进程.内存结构和文件: Oracle服务器由一个Oracle实例和一个Oracle ...

  9. Python设计模式-装饰器模式

    装饰器模式 装饰器模式,动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更为灵活. 代码示例 #coding:utf-8 #装饰器模式 class Beverage():   ...

  10. Python基础教程-Dict和Set

    Python的dict Python内置了字典:dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度. 比如,要根据同学的名字查找对应的 ...