目录
进程间通信:pipe(管道)、fifo(命名管道)、mmap(共享内存映射)、信号、本地套接字(domain)
本地套接字实现C/S模型对比网络编程TCP C/S模型,注意以下几点:
socket函数中:
参数domain: 由AF_INET更改为AF_UNIX或者AF_LOCAL
type:在本地套接字中SOCK_STREAM或者SOCK_DGRAM 都可以
bind函数中:
在本地套接字bind中地址结构由sockaddr_in变为sockaddr_un
可以通过man unix查看sockaddr_un的结构
struct sockaddr_un{
__kernel_sa_family_t sun_family; //AF_UNIX 地址结构类型
char sun_path[UNIX_PATH_MAX]; //pathname socket文件名(含路径)
}
在本地套接字中bind()函数调用成功时,会创建一个socket,因此为保证bind成功,通常我们在bind之前,可以使用unlink()!!!!!!
struct sockaddr_un srv_addr;
srv_addr.sun_family = AF_UNIX;
strcpy(srv_addr.sun_path, "srv.socket");
以下程序将UNIX Domain socket 绑定到一个地址
size = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
#define offsetof(type, member) ((int) & ((type *)0)->MEMBER)
bind(fd, (struct sockaddr *)&srv_addr, size);
本地套接字实现C/S模型
server端
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/un.h>
#include <stddef.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include "wrap.h"
#define SERV_ADDR "serv.socket"
int main(void){
int lfd, cfd, len, size, i;
struct sockaddr_un servaddr, cliaddr;
char buf[4096];
lfd = Socket(AF_UNIX, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_UNIX;
strcpy(servaddr.sun_path, SERV_ADDR);
len = offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path);
unlink(SERV_ADDR);
Bind(lfd, (struct sockaddr *)&servaddr, len);
Listen(lfd, 20);
printf("Accept ...\n");
while(1){
//AF_UNIX大小+108字节
len = sizeof(cliaddr);
cfd = Accept(lfd, (struct sockaddr *)&cliaddr, (socklen_t *)&len);
//得到文件的长度
len -= offsetof(struct sockaddr_un, sun_path);
cliaddr.sun_path[len] = '\0'; //确保打印时,没有乱码出现
printf("client bind filename %s\n", cliaddr.sun_path);
while((size = read(cfd, buf, sizeof(buf))) > 0){
for(i = 0; i < size; i++){
buf[i] = toupper(buf[i]);
}
write(cfd, buf, size);
}
close(cfd);
}
close(lfd);
return 0;
}
client端
本地套接字不能依赖隐式绑定,并且应该在通信建立过程中,创建且初始化2个地址结构。绑定文件描述名(创建两个伪文件,不进行存储,不占有空间地址)
<1>client_addr --> bind()
<2>server_addr --> connect()
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/un.h>
#include <stddef.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include "wrap.h"
#define SERV_ADDR "serv.socket"
#define CLIE_ADDR "clie.socket"
int main(void){
struct sockaddr_un servaddr, cliaddr;
int cfd, len;
char buf[4096];
cfd = Socket(AF_UNIX, SOCK_STREAM, 0);
bzero(&cliaddr,sizeof(cliaddr));
cliaddr.sun_family = AF_UNIX;
strcpy(cliaddr.sun_path, CLIE_ADDR);
//计算客户端地址结构有效长度
len = offsetof(struct sockaddr_un, sun_path) + strlen(cliaddr.sun_path);
unlink(CLIE_ADDR);
Bind(cfd, (struct sockaddr *)&cliaddr, len);
//构造server地址
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_UNIX;
strcpy(servaddr.sun_path, SERV_ADDR);
len = offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path);
Connect(cfd, (struct sockaddr *)&servaddr, len);
while(fgets(buf, sizeof(buf), stdin) != NULL){
write(cfd, buf, strlen(buf));
len = read(cfd, buf, sizeof(buf));
write(STDOUT_FILENO, buf, len);
}
close(cfd);
return 0;
}
unlink函数
功能描述:
从文件系统中删除一个名称。如果名称是文件的最后一个连接,并且没有其它进程将文件打开,名称对应的文件会实际被删除。
不使用unlink可能出现的情况
//之前已经运行过,本地套接字产生的伪文件已经存在
bind error: Address already in use