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, ...
随机推荐
- Xcode The operation couldn’t be completed. (NSURLErrorDomain error -1012.)
使用Xcode SVN 出现问题 The operation couldn’t be completed. (NSURLErrorDomain error -1012.) 解决方法: 打开终端 然后输 ...
- JavaScript------分页插件下载地址
转载: https://github.com/pgkk/kkpager
- 第九篇:使用 lstat 函数获取文件信息
前言 在之前的文章中,描述过如何用 fcntl 函数改变文件的状态标记.但,文件还有很多信息,如文件类型,权限设置,设备编号,访问时间等等.如果要获取这些信息,则使用函数 lstat 可以轻松达到这个 ...
- Centos 虚拟机网络问题,网卡起不来,重启network服务失败
拷贝了个虚拟机,有两个网卡,1个可以起来,另一个起不来.运行命令:$>systemctl restart network 输出如下:Job for network.service failed ...
- 54、Android 粒子效果之雨(下雨的效果)
核心内容: 1.绘制下雨场景的个体.雨点(直线) 2.让直线动起来 3.处理边界问题 4.构造雨点对象 5.雨点大小设置 6.速度设置和角度设置等 7.添加多个雨点 8.抽离可以在 XML 中影响的属 ...
- 基础知识《十四》Java异常的栈轨迹fillInStackTrace和printStackTrace的用法
本文转自wawlian 捕获到异常时,往往需要进行一些处理.比较简单直接的方式就是打印异常栈轨迹Stack Trace.说起栈轨迹,可能很多人和我一样,第一反应就是printStackTrace()方 ...
- python序列中添加高斯噪声
def wgn(x, snr): snr = 10**(snr/10.0) xpower = np.sum(x**2)/len(x) npower = xpower / snr return np.r ...
- SpringMVC JSONP JSON支持
1.ajax端 $.ajax({ type: "post", dataType: "jsonp", //传递给请求处理程序,用以获得jsonp回调函数名的参数名 ...
- Oracle数据库 number 长度与 Short Integer Long BigDecimal 对应关系
转自:https://blog.csdn.net/edward9145/article/details/21398657 Oracle数据库 number 长度与 Short Integer Long ...
- Go语言性能测试
对于一些服务来说,性能是极其重要的一环,事关系统的吞吐.访问的延迟,进而影响用户的体验. 写性能测试在Go语言中是很便捷的,go自带的标准工具链就有完善的支持,下面我们来从Go的内部和系统调用方面来详 ...