使用TCP实现本地通信
socket
#include <sys/types.h
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
参数:
domain:用于指定通信领域
AF_UNIX, AF_LOCAL 本地通信使用
type:指定套接字类型
SOCK_STREAM TCP协议
protocol:附加协议
如果type使用的是 SOCK_STREAM 或者 SOCK_DGRAM
此时该参数可以指定为 0
返回值:
成功 文件描述符
失败 -1
本地通信使用的信息结构体
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[108]; /* 带有路径的文件名 */
};
sun_path[108] 文件名,执行会自动创建 套节字文件
TCP本地通信流程
服务器:
创建套接字 socket( )
填充服务器本地信息结构体 sockaddr_un
将套接字与服务器本地信息结构体绑定 bind( )
将套接字设置为被动监听状态 listen( )
阻塞等待客户端的连接请求 accept( )
进行通信 recv( )/send( )
关闭套接字 close()
客户端:
创建套接字 socket( )
填充客户端本地信息结构体 sockaddr_un
将套接字与客户端本地信息结构体绑定 bind() //客户端执行绑定,是为了服务器能获取客户端的信息;如果不绑定 服务器没法回复应答
填充服务器本地信息结构体 sockaddr_un
发送客户端的连接请求 connect( )
进行通信 send( )/recv( )
关闭套接字 close()
代码实现
服务器—01server.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
/* struct sockaddr_un */
#include <sys/socket.h>
#include <sys/un.h>
#define ERRLOG(errmsg) \
do \
{ \
printf("%s--%s(%d):", __FILE__, __func__, __LINE__); \
perror(errmsg); \
exit(-1); \
} while (0)
//创建套接字-填充服务器网络信息结构体-绑定-监听
int socket_bind_listen(const char *argv[]);
int main(int argc, const char *argv[])
{
//创建套接字-填充服务器网络信息结构体-绑定-监听
int sockfd = socket_bind_listen(argv);
//用来保存客户端信息的结构体
struct sockaddr_un client_addr;
memset(&client_addr, 0, sizeof(client_addr));
socklen_t client_addr_len = sizeof(client_addr);
/*----------------------------------------------------------------------------*/
//阻塞等待客户端的连接请求
int acceptfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len);
if(-1 == acceptfd)
ERRLOG("accept error");
printf("客户端[%s]连接到服务器...\n", client_addr.sun_path);
/*----------------------------------------------------------------------------*/
//通信
char buff[128] = {0};
while (1)
{
//接收应答
if (-1 == recv(acceptfd, buff,sizeof(buff), 0))
ERRLOG("recv error");
printf("客户端 (%s) 发来数据:[%s]\n", client_addr.sun_path, buff);
//组装回复给客户端的应答
strcat(buff, "---996");
//发送数据
if (-1 == send(acceptfd, buff, sizeof(buff),0))
ERRLOG("send error");
}
//关闭监听套接字 一般不关闭
close(sockfd);
return 0;
}
//创建套接字-填充服务器网络信息结构体-绑定
int socket_bind_listen(const char *argv[])
{
// 1.创建套接字 /本地通信 /TCP
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (-1 == sockfd)
ERRLOG("socket error");
// 2.填充 服务器 网络信息结构体
struct sockaddr_un server_addr;
memset(&server_addr, 0, sizeof(server_addr));//清空
server_addr.sun_family = AF_UNIX; //本地通信
strcpy(server_addr.sun_path, "./my_local"); //套节字文件
//结构体长度
socklen_t server_addr_len = sizeof(server_addr);
// 3.将套接字和网络信息结构体绑定
if (-1 == bind(sockfd, (struct sockaddr *)&server_addr, server_addr_len))
ERRLOG("bind error");
/*----------------------------------------------------------------------------*/
// 4.将套接字设置成被动监听状态
if(-1 == listen(sockfd, 5))
ERRLOG("listen error");
/*----------------------------------------------------------------------------*/
return sockfd;
}
客户端—02client.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
/* struct sockaddr_un */
#include <sys/socket.h>
#include <sys/un.h>
#define ERRLOG(errmsg) \
do \
{ \
printf("%s--%s(%d):", __FILE__, __func__, __LINE__); \
perror(errmsg); \
exit(-1); \
} while (0)
//创建套接字-填充服务器网络信息结构体-绑定
int socket_bind(const char *argv[]);
int main(int argc, const char *argv[])
{
//创建套接字-填充服务器网络信息结构体-绑定
int sockfd = socket_bind(argv);
// 填充 服务器 信息结构体
struct sockaddr_un server_addr;
memset(&server_addr, 0, sizeof(server_addr));//清空
server_addr.sun_family = AF_UNIX; //本地通信
strcpy(server_addr.sun_path, "./my_local"); //套节字文件
// 结构体长度
socklen_t server_addr_len = sizeof(server_addr);
/*----------------------------------------------------------------------------*/
// 与服务器建立连接 /服务器 信息结构体
if(-1 == connect(sockfd, (struct sockaddr *)&server_addr, server_addr_len))
ERRLOG("connect error");
/*----------------------------------------------------------------------------*/
//通信
char buff[128] = {0};
while (1)
{
printf("请输入 : ");
fgets(buff,sizeof(buff), stdin);
buff[strlen(buff) - 1] = '\0'; //清除 \n
//发送数据
if (-1 == send(sockfd, buff,sizeof(buff), 0))
ERRLOG("send error");
//接收应答
if (-1 == recv(sockfd, buff,sizeof(buff), 0))
ERRLOG("recv error");
printf("服务器应答[%s]\n", buff);
}
//关闭监听套接字 一般不关闭
close(sockfd);
return 0;
}
//创建套接字-填充服务器网络信息结构体-绑定
int socket_bind(const char *argv[])
{
// 1.创建套接字 /本地通信 /TCP
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (-1 == sockfd)
ERRLOG("socket error");
//2.填充 客户端自己 网络信息结构体
struct sockaddr_un client_addr;
memset(&client_addr, 0, sizeof(client_addr)); //清空
client_addr.sun_family = AF_UNIX; //本地通信
strcpy(client_addr.sun_path, "./my_local_cli");//套节字文件
socklen_t client_addr_len = sizeof(client_addr);
// 3.将套接字和本地信息结构体绑定(客户端)
if (-1 == bind(sockfd, (struct sockaddr *)&client_addr, client_addr_len))
ERRLOG("bind error");
return sockfd;
}
执行结果
注意
1. 客户端侧,不仅 要将 自己的信息 结构体 与 sockfd套接字 绑定 ;还得 填充 服务器信息 信息结构体
填充 服务器信息 信息结构体 :以便于与服务器建立连接
connect(sockfd, (struct sockaddr *)&server_addr, server_addr_len)
2. 报错 :
bind error: Address already in use
因为已经执行一次 套节字文件 已经存在
所以 只需要删除 套节字文件 即可