前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux/unix下的IPC-UNIX Domain Socket

Linux/unix下的IPC-UNIX Domain Socket

作者头像
我与梦想有个约会
发布2023-10-20 18:20:19
1800
发布2023-10-20 18:20:19
举报
文章被收录于专栏:jiajia_dengjiajia_deng

UNIX Domain Socket 是基于socket发展而来的,是linux/unix下一种IPC(Inter-Process Communication 进程间通讯)机制,它无需向内核网络协议栈一样拆包打包,只是将数据从一个进程拷贝到另外一个进程。在这种模式下,无论使用 SOCKET_STREAM 还是 SOCKET_DGRAM 都是可以的,因为同一台电脑上基本上不存在数据丢失的情况,下面的案例实现了一个最小化的 domain socket 模型。


公共头文件

代码语言:javascript
复制
/* wrap.h */
#ifndef __WRAP_H__
#define __WRAP_H__
void perr_exit(const char* s);
int Accept(int fd, struct sockaddr* sa, socklen_t* salenptr);
void Bind(int fd, const struct sockaddr* sa, socklen_t salen);
void Connect(int fd, const struct sockaddr* sa, socklen_t salen);
void 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);
void Close(int fd);
ssize_t Readn(int fd, void* vptr, size_t n);
ssize_t Writen(int fd, const void* vptr, size_t n);
static ssize_t my_read(int fd, char* ptr);
ssize_t Readline(int fd, void* vptr, size_t maxlen);
#endif
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include “wrap.h”
void perr_exit(const char* s)
{
perror(s);
exit(1);
}
int Accept(int fd, struct sockaddr* sa, socklen_t* salenptr)
{
int n;
again:
if ( (n = accept(fd, sa, salenptr)) < 0 )
{
if ((errno == ECONNABORTED)  (errno == EINTR))
{
goto again;
}
else
{
perr_exit(“accept error”);
}
}
return n;
}
void Bind(int fd, const struct sockaddr* sa, socklen_t salen)
{
if ( bind(fd, sa, salen) < 0 )
{
perr_exit(“bind error”);
}
}
void Connect(int fd, const struct sockaddr* sa, socklen_t salen)
{
if ( connect(fd, sa, salen) < 0 )
{
perr_exit(“connect error”);
}
}
void Listen(int fd, int backlog)
{
if ( listen(fd, backlog) < 0 )
{
perr_exit(“listen error”);
}
}
int Socket(int family, int type, int protocol)
{
int n = socket(family, type, protocol);
if ( n < 0 )
{
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)) == -1)
{
if (errno == EINTR)
{
goto again;
}
else
{
return -1;
}
}
return n;
}
ssize_t Write(int fd, const void* ptr, size_t nbytes)
{
ssize_t n;
again:
if ( (n = write(fd, ptr, nbytes)) == -1)
{
if (errno == EINTR)
{
goto again;
}
else
{
return -1;
}
}
return n;
}
void Close(int fd)
{
if (close(fd) == -1)
{
perr_exit(“close error”);
}
}
ssize_t Readn(int fd, void* vptr, size_t n)
{
size_t nleft;
ssize_t nread;
char* ptr;
ptr = vptr;
nleft = n;
while (nleft > 0)
{
if ( (nread = read(fd, ptr, nleft)) < 0 )
{
if (errno == EINTR)
{
nread = 0;
}
else
{
return -1;
}
}
else if (nread == 0)
{
break;
}
nleft -= nread;
ptr += nread;
}
}
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 > 0)
{
if ( (nwritten = write(fd, ptr, nleft)) <= 0)
{
if (nwritten < 0 && errno == EINTR)
{
nwritten = 0;
}
else
{
return -1;
}
}
nleft -= nwritten;
ptr += nwritten;
}
return n;
}
static ssize_t my_read(int fd, char* ptr)
{
static int read_cnt;
static char* read_ptr;
static char read_buf[100];
if (read_cnt <= 0)
{
again:
if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0 )
{
if (errno == EINTR)
{
goto again;
}
return -1;
}
else if (read_cnt == 0)
{
return 0;
}
read_ptr = read_buf;
}
read_cnt–;
*ptr = *read_ptr++;
return 1;
}
ssize_t Readline(int fd, void* vptr, size_t maxlen)
{
ssize_t n, rc;
char c, *ptr;
ptr = vptr;
for (n = 1; n < maxlen; n++)
{
if ( (rc = my_read(fd, &c)) == 1)
{
*ptr++ = c;
if (c == ‘\n’)
{
break;
}
}
else if (rc == 0)
{
*ptr = 0;
return n - 1;
}
else
{
return -1;
}
*ptr = 0;
return n;
}
}
服务端代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <stddef.h>
#include “wrap.h”
// 服务端要绑定的socket套接字文件
#define SERV_ADDR “foo.socket”
int main(int argc, char* argv[])
{
// 创建socket以 AF_UNIX 方式
int sock = Socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un srvaddr;
memset(&srvaddr, 0, sizeof(srvaddr));
srvaddr.sun_family = AF_UNIX;
strcpy(srvaddr.sun_path, SERV_ADDR);
/* offsetof 是一个宏,可以计算出第一个参数中的结构体中第二个参数的偏移位置 */
int len = offsetof(struct sockaddr_un, sun_path) +
strlen(srvaddr.sun_path);
// 删除当前目录下的socket文件,防止bind失败
unlink(SERV_ADDR);
Bind(sock, (struct sockaddr*)&srvaddr, len);
Listen(sock, 20);
printf(“Accept…..\n”);
struct sockaddr_un cntaddr;
int conn;
int size;
char buf[4096];
while (1)
{
len = sizeof(cntaddr);
conn = Accept(sock, (struct sockaddr*)&cntaddr, &len);
len -= offsetof(struct sockaddr_un, sun_path);
cntaddr.sun_path[len] = ‘\0’;
printf(“client bind filename %s\n”, cntaddr.sun_path);
// 接收
while ((size = read(conn, buf, sizeof(buf))) > 0)
{
for (int i = 0; i < size; i++)
{
buf[i] = toupper(buf[i]);
}
// 发送
Write(conn, buf, size);
}
}
return 0;
}
客户端代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <stddef.h>
#include “wrap.h”
// 要连接的服务器socket套接字文件
#define SERV_ADDR “foo.socket”
// 客户端要绑定的socket套接字文件
#define CLIENT_ADDR “client.socket”
int main(int argc, char* argv[])
{
int len;
// 同样以 AF_UNIX 方式创建 socket
int sock = Socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un srvaddr, cntaddr;
memset(&srvaddr, 0, sizeof(srvaddr));
memset(&cntaddr, 0, sizeof(cntaddr));
// 构建客户端的结构体
cntaddr.sun_family = AF_UNIX;
strcpy(cntaddr.sun_path, CLIENT_ADDR);
len = offsetof(struct sockaddr_un, sun_path) +
strlen(cntaddr.sun_path);
// 绑定客户端socket套接字文件
unlink(CLIENT_ADDR);
Bind(sock, (struct sockaddr*)&cntaddr, len);
// 构建要连接的服务端结构体
srvaddr.sun_family = AF_UNIX;
strcpy(srvaddr.sun_path, SERV_ADDR);
len = offsetof(struct sockaddr_un, sun_path) +
strlen(srvaddr.sun_path);
// 连接服务端
Connect(sock, (struct sockaddr*)&srvaddr, len);
char buf[4096];
while (fgets(buf, sizeof(buf), stdin) != NULL)
{
// 写
Write(sock, buf, strlen(buf));
// 读
len = read(sock, buf, sizeof(buf));
// 输出到屏幕
Write(STDOUT_FILENO, buf, len);
}
Close(sock);
return 0;
}

编译测试

编译客户端:gcc domian_client.c wrap.c -o domain_client 编译服务端:gcc domain_server.c wrap.c -o domain_server -std=c99 测试效果:

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015-07-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 公共头文件
  • 编译测试
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档