Linux 网络编程 全解(十)--------本地套接字(domain)

版权声明:本BLOG上原创文章未经本人许可,不得转载,否则属于侵权行为 https://blog.csdn.net/weixin_40204595/article/details/84449705

写在前面:本篇主要介绍本地套接字的作用,以及本地套接字跟网路套接字在实现方式上哪里不一样,以及用本地套接字来实现服务器和客户端。

正文:

1、本地套接字的作用:本地套接字的CS模型使用来实现进程间通信IPC的,另外实现进程间通信的别的方式还有:pipe、fifo、mmap(内存映射)、信号等。

2、对比网络套接字的CS模型,本地套接字需要注意的地方。

   (1)、创建套接字的时候:int socket(int domain, int type , int protocol); 

           domain:不再是AF_INET,而是 AF_UNIX,或者AF_LOCAL  。

            type:SOCK_STREAM 或者 SOCK_DGRAM 都可以

            protocol:0

  (2)、bind绑定地址结构的时候: int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); 

           这里的addr:不再是 struct sockaddr_in 类型,而是 struct sockaddr_un 类型,来看一下这种类型:

              struct sockaddr_un {
                                __kernel_sa_family_t sun_family;
                             char sun_path[UNIX_PATH_MAX]; 
             };

           这里的sun_family就是AF_UNIX,而 sun_path ;就是socket文件名。

         这里要注意:因为 sun_path  server和client都要有,所以client端不能再隐式绑定,也就是说client端必须要调用bind函数来显式绑定自己的地址结构。

        另外,bind的第三个参数:addrlen,不能再用sizeof(struct sockaddr_un)来计算,而是用如下方式:

      int len = offsetof(struct sockaddr_un, sun_path) + strlen(ser_addr.sun_path); //offsetof宏的头文件#include <stddef.h>

   (3)、对比一下这几种socket addr数据结构

      

3、本地套接字Server和Client的实现,同样,代码的注释也尽可能详细了。

     domain server实现:

#include <stdio.h>
#include <sys/types.h>        
#include <sys/socket.h>
#include <sys/un.h>
#include <stddef.h>
#include <unistd.h>

#define SER_PATH  "ser_socket"


/*struct sockaddr_un类型*/
/*
	struct sockaddr_un {
		   __kernel_sa_family_t sun_family;
		   char sun_path[UNIX_PATH_MAX]; 
	};
*/

int main(void)
{
	int lfd = -1, cfd = -1;
	struct sockaddr_un ser_addr, cli_addr;
	int ser_addr_len = 0, cli_addr_len = 0;
	char *w_buf = "server receive OK";
	unsigned char r_buf[1024] = {0};
	ssize_t rd_len = 0;
	int ret = 0;
	
	//本地的socket 的第一个参数为:AF_UNIX或者AF_LOCAL
	//第二个参数:SOCK_STREAM 或者 SOCK_DGRAM 都可以
	//第三个参数:默认0 就可以
	lfd = socket(AF_UNIX,SOCK_STREAM,0);
	if(lfd < 0)
	{
		printf("socket error\n");
		
		return -1;
	}
	
	//绑定地址结构
	memset(&ser_addr,0,sizeof(struct sockaddr_un));
	ser_addr.sun_family = AF_UNIX;
	strcpy(ser_addr.sun_path,SER_PATH);
	//计算domain socket的地址结构的长度的方法如下:
	ser_addr_len =  offsetof(struct sockaddr_un, sun_path) + strlen(ser_addr.sun_path);
	printf("ser_addr_len = %d\n",ser_addr_len);

	//为了保证bind的成功率,bind前调用一次 unlink
	unlink(SER_PATH);
	ret = bind(lfd, (const struct sockaddr *)&ser_addr,ser_addr_len);
	if(ret < 0)
	{
		printf("bind error \n");
		
		return -1;
	}
	
	listen(lfd, 20);
	
	//服务器等待客户端连接
	cfd = accept(lfd, (struct sockaddr *)&cli_addr, &cli_addr_len);
	//计算出客户端的 sun_path 长度
	cli_addr_len -= offsetof(struct sockaddr_un, sun_path);
	cli_addr.sun_path[cli_addr_len] = '\0';
	printf("client filename :%s\n",cli_addr.sun_path);
	
	while(1)
	{
		memset(r_buf,0,1024);
		//服务器接收客户端发过来的数据
		rd_len = read(cfd, r_buf, 1024);
		printf("server receive context:%s\n",r_buf);
		//给客户端回复
		write(cfd, w_buf, strlen(w_buf));
		
	}
	
	return 0;
}

domain client的实现

#include <stdio.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <sys/un.h>
#include <stddef.h>

/*struct sockaddr_un类型*/
/*
	struct sockaddr_un {
		   __kernel_sa_family_t sun_family;
		   char sun_path[UNIX_PATH_MAX]; 
	};
*/
#define CLI_PATH  "cli_socket"
#define SER_PATH  "ser.socket"

int main(void)
{
	int cfd = -1;
	struct sockaddr_un cli_addr , ser_addr;
	int cli_addr_len = 0,ser_addr_len = 0;
	char *w_buf = "Hello this is client";
	int rd_len = 0;
	unsigned char r_buf[1024] = {0};
	
	cfd = socket(AF_UNIX,SOCK_STREAM,0);
	if(cfd < 0)
	{
		printf("socket error\n");
		
		return -1;
	}	
	//客户端也要绑定自己的地址结构
	//否在无法跟自己对应的文件名建立关系
	memset(&cli_addr,0,sizeof(cli_addr));
	cli_addr.sun_family = AF_UNIX;
	strcpy(cli_addr.sun_path,CLI_PATH);
	//地址结构长度计算
	cli_addr_len = offsetof(struct sockaddr_un,sun_family) + strlen(cli_addr.sun_path);
	
	unlink(CLI_PATH);
	if(bind(cfd, (const struct sockaddr *)&cli_addr,cli_addr_len) < 0)
	{
		printf("bind error\n");
		
		return -1;
	}
	
	//连接服务器
	//注意:连接服务器的时候也要传入服务器的地址结构
	memset(&ser_addr,0,sizeof(ser_addr));
	ser_addr.sun_family = AF_UNIX;
	strcpy(ser_addr.sun_path,SER_PATH);
	ser_addr_len = offsetof(struct sockaddr_un,sun_family) + strlen(ser_addr.sun_path);
	connect(cfd, (const struct sockaddr *)&ser_addr,ser_addr_len);
	
	while(1)
	{
		write(cfd, w_buf, strlen(w_buf));
		
		memset(r_buf,0,1024);
		rd_len = read(cfd, r_buf, 1024);
		
		sleep(4); //每隔4秒通信一次
		
	}	
	
	
	
	
	return 0;
}

   

猜你喜欢

转载自blog.csdn.net/weixin_40204595/article/details/84449705