socket IPC(本地套接字 domain)
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)的更多相关文章
- 【转】PHP实现系统编程(四)--- 本地套接字(Unix Domain Socket)
原文:http://blog.csdn.net/zhang197093/article/details/78143687?locationNum=6&fps=1 --------------- ...
- 本地套接字-本地socket
本地套接字简单应用场景 一 #服务端--简单 import socket import os a='sock_file' if os.path.exists(a): os.remove(a) s=so ...
- (十三) [终篇] 一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- Unix 环境高级编程 (APUE) 之 网络 IPC:套接字
一起学 Unix 环境高级编程 (APUE) 之 网络 IPC:套接字 . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级 ...
- IPC——数据报套接字通信
Linux进程间通信——使用数据报套接字 前一篇文章,Linux进程间通信——使用流套接字介绍了一些有关socket(套接字)的一些基本内容,并讲解了流套接字的使用,这篇文章将会给大家讲讲,数据报套接 ...
- IPC——流套接字通信
Linux进程间通信——使用流套接字 前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进 ...
- 网络IPC:套接字之套接字描述符
套接字是通信端点的抽象.与应用程序要使用文件描述符访问文件一样,访问套接字也需要套接字描述符.套接字描述符在UNIX系统是用文件描述符实现的.事实上,许多处理文件描述符的函数(如read和write) ...
- UNIX环境高级编程 第16章 网络IPC:套接字
上一章(15章)中介绍了UNIX系统所提供的多种经典进程间通信机制(IPC):管道PIPE.命名管道FIFO.消息队列Message Queue.信号量Semaphore.共享内存Shared Mem ...
- Linux 进程间通信(二)(网络IPC:套接字)
socket描述符 套接字是通信端点的抽象,创建一个套接字使用如下函数: #include <sys/socket.h> int socket(int domain, int type, ...
随机推荐
- Python学习-一个简单的计时器
在实际开发中,往往想要计算一段代码执行多长时间,以下我将该功能写入到一个函数里面,仅仅要在每一个函数前面调用该函数就可以,见以下代码: #------------------------------- ...
- 认识tornado(二)
前面我们对 Tornado 自带的 hello world 作了代码组织上的解释,但是没有更加深入细致地解释.这里我们直接从main()函数开始,单步跟随,看看tornado都干了些什么. 下面是 m ...
- jQuery的validate验证插件使用方法
(1)默认校验规则(1)required:true 必输字段(2)remote:"check.php" 使用ajax方法调用check.php验证输入值(3)email:true ...
- C# .net 数组倒序排序
1.数组方法 Array.Sort(Array Array); 此方法为数组的排序(正序)方法 Array.Reverse(Array Array); 此方法可以将数组中的值颠倒 两个方法结合使用 ...
- 巨蟒python全栈开发-第11天 第一类对象 闭包 迭代器
一.今日主要内容总览(重点) 1.第一类对象->函数名=>变量名 (1)函数对象可以像变量一样进行赋值 (2)还可以作为列表的元素进行使用 (3)还可以作为返回值返回 (4)还可以作为参数 ...
- 并发编程5 操作系统&进程
一.今日大纲 1.multiprocessing模块简单应用 2.for循环创建进程 3.进程传参方式和创建方式2 4.join方法 5.操作系统基础 二.今日内容 (1)操作系统简单介绍 多道技术: ...
- 第三课——SQL操作和数据类型
[SQL分类:DDL DML DCL] 一.DDL(数据库定义语言) 定义不同的数据段.数据库.表.列.索引等数据库对象,常用语句关键字:create drop alter等 1.修改表字段,alte ...
- Contos更换python版本
1.查看版本 #python -VPython 2.6.6 2.安装前准备,安装相关库#yum install gcc gcc-c++ autoconf automake#yum install op ...
- 高德地图 js api 使用
使用高德地图js api 制作网页上的地图应用. 1.先申请一个 开发者用的 key . 2. 在页面中引入高德提供的地图js <script src="http://webapi. ...
- IO流入门-第十二章-ObjectInputStream_ObjectOutputStream
DataInputStream和DataOutputStream基本用法和方法示例,序列化和反序列化 import java.io.Serializable; //该接口是一个“可序列化”的 ,没有任 ...