本地套接字
利用cs模型实现本地套接字完成进程间通信
对比网络编程TCP C/S模型,注意以下几点
1、int socket(int domain, int type, int protocol); domain-->AF_INET改为AF_UNIX ,
type都可写SOCK_STREAM/SOCK_DGRAM
2、地址结构 sockaddr_in -->sockaddr_un
struct sockaddr_un serv_addr;
serv_addr.sun_family = AF_UNIX
strcpy(serv_addr.sun_path , "serv.socket")
len = offsetof(struct sockaddr_un , sun_path) + strlen("serv.socket")
offsetof(struct sockaddr_un , sun_path)求出来就是2,首地址偏移
3、bind(sockfd , (struct sockaddr*) &serv_addr , len);
bind()函数调用成功,会创建一个sockfd,因此为了保证bind成功,通常在bind之前使用unlink("serv.socket");
4、客户端不能依赖隐式绑定,并且应该在通信建立过程中,初始化2个地址结构
1)、client_addr--->bind()
2)、serv_addr--->connect()
本地套接字实现进程间通信服务器模型
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/un.h>
#include<ctype.h>
#include<stddef.h>
#define SERV_ADDR "serv.socket"
int main(int argc , char *argv[])
{
struct sockaddr_un serv_addr , clit_addr;
int sockfd , cfd;
char buf[BUFSIZ];
int i , n , len;
sockfd = socket(AF_UNIX , SOCK_STREAM , 0);
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path , SERV_ADDR);
len = offsetof(struct sockaddr_un , sun_path) + strlen(SERV_ADDR);
unlink(SERV_ADDR);
bind(sockfd , (struct sockaddr*)&serv_addr , len);
listen(sockfd , 128);
printf("Accepting connections....\n");
while(1){
len = sizeof(clit_addr);
cfd = accept(sockfd , (struct sockaddr*)&clit_addr , (socklen_t*)&len);
len -= offsetof(struct sockaddr_un , sun_path);
clit_addr.sun_path[len] = '\0';
printf("client bind filename %s\n" , clit_addr.sun_path);
while((n = read(cfd , buf , sizeof(buf)))>0){
if(n > 0){
for(i = 0 ; i < n ; i++)
buf[i] = toupper(buf[i]);
}
write(cfd , buf , n);
write(STDOUT_FILENO , buf , n);
}
}
close(sockfd);
return 0 ;
}
本地套接字实现进程间通信客户端模型
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/un.h>
#include<stddef.h>
#define SERV_PORT 9004
#define SERV_ADDR "serv.socket"
#define CLIT_ADDR "clit.socket"
void sys_err(char*s)
{
perror(s);
exit(1);
}
int main(int argc , char *argv[])
{
int n , ret , cfd , len;
char buf[BUFSIZ];
struct sockaddr_un serv_addr , clit_addr;
cfd = socket(AF_UNIX , SOCK_STREAM , 0);
clit_addr.sun_family = AF_UNIX;
strcpy(clit_addr.sun_path , CLIT_ADDR);
len = offsetof(struct sockaddr_un , sun_path) + strlen(CLIT_ADDR);
unlink(CLIT_ADDR);
ret = bind(cfd , (struct sockaddr*)&clit_addr , len);
if(ret == -1)
sys_err("bind error");
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path , SERV_ADDR);
len = offsetof(struct sockaddr_un , sun_path) + strlen(SERV_ADDR);
if((connect(cfd , (struct sockaddr*)&serv_addr , (socklen_t)len))== -1)
sys_err("connect error");
while(fgets(buf , sizeof(buf) , stdin) != NULL ){
n = write(cfd , buf , strlen(buf));
if(n == -1)
sys_err("write error");
len = read(cfd , buf , (sizeof(buf)));
if(n == -1)
sys_err("read error");
write(STDOUT_FILENO , buf , len);
}
close(cfd);
return 0 ;
}
这里要注意其和网络通信中的区别,在客户端中不仅要绑定且初始化自己的地址结构,也要初始化服务器端的地址结构,不能依赖隐式绑定。
还需要注意,在这个模型中bind之前都需要进行unlink操作。