linux unix domain,Linux/unix下的IPC-UNIX Domain Socket

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

公共头文件

/* 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

#include

#include

#include

#include

#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

#include

#include

#include

#include

#include

#include

#include

#include

#include

#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

#include

#include

#include

#include

#include

#include

#include

#include

#include

#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

测试效果:

c8ba717b92cddf0509935bde2efb62bd.png

相关

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值