一、进程间通信-Socket套接字
基本特点: socket是一种接口技术,抽象成一个文件操作,可以让同一台计算机的进程之间通信
也可以让不同计算机的进程通信(网络通信)
二、socket在同一计算机中的进程间通信
底层需要借助socket文件,进行同一计算机下的进程间通信
int socket(int domain, int type, int protocol);
功能: 创建socket对象
domain:
AF_UNIX/AF_LOCAL 本地通信、进程间通信
AF_INET 基于IPv4地址通信
AF_INET6 基于IPv6地址通信
type:
SOCK_STREAM 基于数据流协议 本地
SOCK_DGRAM 基于数据报协议
protocol:
特殊通信协议,一般不用,也0或者NULL即可
返回值: 成功返回socket描述符,失败返回-1
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:绑定socket和通信地址(不绑定无法使用)
sockfd: socket描述符
addr: 地址结构体指针
实际传递的是 sockaddr_un或者sockaddr_in 结构体指针
但是需要把它们统一转换成sockaddr*类型,但是C语言没有自动类型识别转换,需要进行强转
// 本地通信地址结构体类型
#include
struct sockaddr_un {
__kernel_sa_family_t sun_family; /*地址簇 domain写什么这就写什么*/
char sun_path[UNIX_PATH_MAX]; /*socket文件地址*/
};
// 网络地址结构体类型
#include
struct sockaddr_in {
__kernel_sa_family_t sin_family; /*地址簇 domain写什么这就写什么*/
__be16 sin_port; /*端口号*/
struct in_addr sin_addr; /*IP地址*/
};
struct in_addr {
__be32 s_addr;
};
addrlen: 地址结构体的字节数,用于区分 sockaddr_un还是sockaddr_in
返回值: 成功返回0 失败-1
int listen(int sockfd, int backlog);
功能: 监听socket,数据流通信时使用
sockfd: socket描述符
backlog: 等待连接socket的排队数量,默认最大128
返回值: 成功返回0 失败-1
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:等待连接,数据流通信时使用
sockfd: socket描述符
addr: 获取连接者的地址
addrlen: 既是输入,也是输出
既告诉accept函数当前计算机地址结构体的字节数,同时也能获取发送者的地址结构体字节数
返回值: 连接成功返回一个连接后的socket描述符
注意:如果没有连接则阻塞
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能: 连接socket
sockfd: 自己的socket描述符
addr: 连接目标的地址结构体指针
addrlen: 地址结构体的字节数,用于区分 sockaddr_un还是sockaddr_in
返回值: 成功返回0 失败-1
/*背下来!!!*/
本地通信编程模型(基于数据流)
进程A 进程B
创建socket 创建socket
准备通信地址(本地socket(文件)地址) 准备对方的通信地址
绑定socket和地址(本机地址) \
开启监听 \
等待连接 通过connect连接
接收/发送数据 发送/接收数据
关闭socket 关闭sokect
删除sokect
进程A
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
-
- int main(int argc,const char* argv[])
- {
- // 创建socket
- int sockfd = socket(AF_UNIX,SOCK_STREAM,0);
- if(0 > sockfd)
- {
- perror("socket");
- return EXIT_FAILURE; // 一个负数
- }
-
- // 准备通信地址
- struct sockaddr_un addr = {};
- addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path,"sock");
- socklen_t addrlen = sizeof(addr);
-
- // 绑定socket和通信地址 0是成功
- if(bind(sockfd,(struct sockaddr*)&addr,addrlen))
- {
- perror("bind");
- return EXIT_FAILURE;
- }
-
- // 开启监听 0是成功
- if(listen(sockfd,5))
- {
- perror("listen");
- return EXIT_FAILURE;
- }
-
- // 等待连接...
- int con_fd = accept(sockfd,(struct sockaddr*)&addr,&addrlen);
- if(0 > con_fd)
- {
- perror("accept");
- return EXIT_FAILURE;
- }
- printf("有人连接成功!\n");
-
- char buf[4096] = {};
- size_t buf_size = sizeof(buf);
-
- for(;;)
- {
- printf("recv:");
- fflush(stdout);
-
- // 接收数据
- read(con_fd,buf,buf_size);
- if(0 == strcmp(buf,"quit"))
- {
- printf("通信结束!\n");
- break;
- }
- printf("%s\n>>>",buf);
-
- // 发送数据
- scanf("%s",buf);
- write(con_fd,buf,strlen(buf)+1);
- if(0 == strcmp(buf,"quit"))
- {
- printf("通信结束!\n");
- break;
- }
- }
- // 关闭socket 关闭任何一个都可以
- close(con_fd);
- close(sockfd);
-
- // 删除socket文件
- unlink(addr.sun_path);
- }
进程B
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
-
- int main(int argc,const char* argv[])
- {
- // 创建socket
- int sockfd = socket(AF_UNIX,SOCK_STREAM,0);
- if(0 > sockfd)
- {
- perror("socket");
- return EXIT_FAILURE; // 一个负数
- }
-
- // 准备通信地址
- struct sockaddr_un addr = {};
- addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path,"sock");
- socklen_t addrlen = sizeof(addr);
-
- // 连接
- if(connect(sockfd,(struct sockaddr*)&addr,addrlen))
- {
- perror("connect");
- return EXIT_FAILURE;
- }
- printf("连接成功!\n");
-
- char buf[4096] = {};
- size_t buf_size = sizeof(buf);
-
- for(;;)
- {
- // 发送数据
- printf(">>>");
- scanf("%s",buf);
- write(sockfd,buf,strlen(buf)+1);
- if(0 == strcmp(buf,"quit"))
- {
- printf("通信结束!\n");
- break;
- }
- printf("recv:");
- fflush(stdout);
-
- // 接收数据
- read(sockfd,buf,buf_size);
- if(0 == strcmp(buf,"quit"))
- {
- printf("通信结束!\n");
- break;
- }
- printf("%s\n",buf);
- }
- // 关闭socket 关闭任何一个都可以
- close(sockfd);
- }