进程间通信-Socket
Socket是一种接口技术,可以让不同的进程进行通信,有两种方式:既可以同一计算机上的,也可以是不同计算机上的进程。
同一计算机上socket通信:
注意:底层需要借助socket文件,进行同一台计算机下不同进程之间的通信
int socket(int domain, int type, int protocol);
功能:创建socket对象
domain:
AF_UNIX,AF_LOCAL 选择使用socket文件进行通信
type:
SOCK_STREAM 数据流
SOCK_DGRAM 数据报
protocol:
特殊协议,一般写0即可
返回值:socket对象的描述符,错误返回负值
准备通信地址:
struct sockaddr_un
{
int sun_family; //与domain一致即可
char sun_path[108]; /* 地址名 */
};
绑定socket对象和通信地址:会自动创建socket文件
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:绑定通信地址和socket
sockfd:socket对象的描述符
addr:
实际传递的是sockaddr_un或sockaddr_in,但是要统一转换成sockaddr
addrlrn:地址结构体的字节数,用于区别sockaddr_un,sockaddr_in。
返回值:成功返回0,失败返回-1
使用于SOCK_DGRAM报文的通信函数
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
功能:发送数据
sockfd:socket对象描述符
buf:要发送的数据首地址
len:要发送数据的字节数
flags:是否阻塞,写0即可
dest_addr:通信目标的地址
addrlen:地址结构体的字节数
返回值:成功发送的字节数,
-1 出现错误
0 通信关闭
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
功能:接收数据
sockfd:socket对象描述符
buf:缓冲区首地址
len:缓冲区大小
flags:是否阻塞,写0即可
src_addr:用于存储发送者的地址
addrlen:既是输入,也是输出,
1、告诉系统src_addr的字节数
2、系统反馈实际到的发送者的地址字节数
返回值:成功接收到的字节数
-1 出现错误
0 通信关闭
本地进程间通信
进程A
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
int main(int argc,const char* argv[])
{
// 创建socket对象
int sock = socket(AF_UNIX,SOCK_DGRAM,0); //UNIX本地使用 DGRAM报文通信
if(0 > sock)
{
perror("socket");
return -1;
}
// 准备通信地址
struct sockaddr_un addr = {}; // sockaddr_un 本地连接时的数据结构
addr.sun_family = AF_UNIX;
sprintf(addr.sun_path,"local_socketA");
socklen_t addrlen = sizeof(addr);
// 绑定socket对象与地址,创建一个用于接收数据的socket文件
if(bind(sock,(struct sockaddr*)&addr,addrlen))
{
perror("bind");
return -1;
}
char buf[4096] = {};
for(;;)
{
// 存储发送的地址
struct sockaddr_un src_addr = {};
// 接收数据和数据来源
int ret = recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr*)&src_addr,&addrlen);
printf("recv:%s len:%d\n",buf,ret);
if(ret <= 0 || 0 == strcmp(buf,"quit"))
{
printf("通信结束!\n");
break;
}
printf(">>>");
gets(buf);
// 返回数据
ret = sendto(sock,buf,strlen(buf)+1,0,(struct sockaddr*)&src_addr,addrlen);
printf("send len:%d\n",ret);
if(ret <= 0 || 0 == strcmp(buf,"quit"))
{
printf("通信结束!\n");
break;
}
}
// 关闭socket对象
close(sock);
// 删除socket文件
remove(addr.sun_path);
}
进程B
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
int main(int argc,const char* argv[])
{
// 创建socket对象
int sock = socket(AF_UNIX,SOCK_DGRAM,0);
if(0 > sock)
{
perror("socket");
return -1;
}
// 准备自己通信地址
struct sockaddr_un addr = {} , dest_addr = {};
addr.sun_family = AF_UNIX;
sprintf(addr.sun_path,"local_socketB");
socklen_t addrlen = sizeof(addr);
// 绑定socket对象与地址,创建一个用于接收数据的socket文件
if(bind(sock,(struct sockaddr*)&addr,addrlen))
{
perror("bind");
return -1;
}
// 目标的地址
dest_addr.sun_family = AF_UNIX;
sprintf(dest_addr.sun_path,"local_socketA");
for(;;)
{
char buf[4096] = {};
printf(">>>");
gets(buf); //数据写入
int ret = sendto(sock,buf,strlen(buf)+1,0,(struct sockaddr*)&dest_addr,addrlen);
printf("send len:%d\n",ret);
if(ret <= 0 || 0 == strcmp(buf,"quit"))
{
printf("通信结束!\n");
break;
}
ret = recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr*)&dest_addr,&addrlen);
printf("recv:%s len:%d\n",buf,ret); //程序B检测输出字符
if(ret <= 0 || 0 == strcmp(buf,"quit"))
{
printf("通信结束!\n");
break;
}
}
close(sock);
remove(addr.sun_path);
}