一、前言
作用:
用于实现一台主机上的两个进程的通信
二、用UDP服务端/客户端模型来实现一台主机上的两个进程的通信
2.1、服务器端
udp_server.c
cs
#include<stdio.h> // 包含标准输入输出库,用于printf等函数
#include <sys/types.h> // 包含系统数据类型定义,如pid_t, socklen_t等
#include <sys/socket.h> // 包含套接字编程相关函数和数据结构
// 注意:这里应该使用<sys/un.h>而不是<linux/un.h>,因为<linux/un.h>是Linux特有的,可能不是所有UNIX系统都支持
#include <sys/un.h> // 包含Unix域套接字相关数据结构
#include <string.h> // 包含字符串操作函数,如strcpy, memset等
#define BUF_SIZE 20 // 定义缓冲区大小为20字节
int main()
{
// 1. 创建socket
int iServer = socket(PF_UNIX, SOCK_DGRAM, 0); // 创建一个Unix域数据报套接字
if (-1 == iServer)
{
printf("create socket error!----------\r\n"); // 如果创建失败,打印错误信息
return -1; // 返回-1表示程序异常退出
}
printf("1:socket ok!--------------\r\n"); // 打印socket创建成功的信息
// 2. 绑定socket到指定路径
struct sockaddr_un stServer; // 定义一个Unix域套接字地址结构
memset(&stServer, 0, sizeof(struct sockaddr_un)); // 初始化地址结构,将其所有字节设置为0
stServer.sun_family = PF_UNIX; // 设置地址家族为Unix域
strcpy(stServer.sun_path, "Afanda"); // 设置套接字文件路径为"Afanda"
unlink(stServer.sun_path); // 如果该路径已存在,则删除它(避免绑定失败)
int ret = bind(iServer, (struct sockaddr *)&stServer, sizeof(struct sockaddr_un)); // 绑定socket到指定路径
if (-1 == ret)
{
printf("bind error!------------\r\n"); // 如果绑定失败,打印错误信息
return -1; // 返回-1表示程序异常退出
}
printf("2:bind ok!-------------\r\n"); // 打印绑定成功的信息
// 3. 使用recvfrom接收数据,并使用sendto发送数据
char buf[BUF_SIZE] = {0}; // 定义一个缓冲区用于接收和发送数据
struct sockaddr_un stClient; // 定义一个结构用于存储客户端的地址信息
socklen_t len = sizeof(struct sockaddr_un); // 设置地址结构的大小
while (1) // 无限循环,等待接收数据
{
if (recvfrom(iServer, buf, BUF_SIZE, 0, (struct sockaddr *)&stClient, &len) > 0) // 接收数据
{
printf("recv data:%s\r\n", buf); // 打印接收到的数据
// 注意:这里发送的数据长度应该是实际接收到的数据长度,而不是BUF_SIZE
ret = sendto(iServer, buf, strlen(buf), 0, (struct sockaddr *)&stClient, len); // 发送数据回客户端
printf("sendto ok,ret=%d\r\n", ret); // 打印发送结果
}
}
// 注意:由于上面是一个无限循环,所以这里的return 0;实际上永远不会被执行到
return 0;
}
2.2、客户端
udp_client.c
cs
#include<stdio.h> // 引入标准输入输出库,用于printf等函数
#include <sys/types.h> // 引入系统数据类型定义,如pid_t, socklen_t等
#include <sys/socket.h> // 引入套接字编程相关函数和数据结构
#include <linux/un.h> // 引入Linux特有的Unix域套接字相关数据结构
// 注意:通常在非Linux系统上,应该使用<sys/un.h>代替
#include <string.h> // 引入字符串操作函数,如strcpy, memset等
#define BUF_SIZE 20 // 定义缓冲区大小为20字节
int main()
{
// 1. 创建socket
// 创建一个Unix域数据报套接字
int iClient = socket(PF_UNIX, SOCK_DGRAM, 0);
if (-1 == iClient)
{
printf("socket error!------------\r\n"); // 如果socket创建失败,打印错误信息
return -1; // 返回-1表示程序异常退出
}
printf("1:socket ok!-----------\r\n"); // 打印socket创建成功的信息
// 注意:在客户端程序中,通常不需要bind操作,因为它只是连接到服务器
// 但为了演示,这里仍然进行了bind操作,但通常这样做是不必要的
// 2. 尝试在客户端上进行bind操作(通常这是不必要的)
struct sockaddr_un stServer; // 用于服务器地址的结构体
memset(&stServer, 0, sizeof(struct sockaddr_un)); // 初始化结构体,将所有字节设置为0
stServer.sun_family = PF_UNIX; // 设置地址家族为Unix域
strcpy(stServer.sun_path, "Afanda"); // 设置服务器套接字文件路径为"Afanda"
// 这里的stClient结构体和bind操作实际上是多余的,因为客户端不需要绑定到特定的路径
// 但为了与您的代码保持一致,我仍然会进行注释
struct sockaddr_un stClient; // 用于客户端地址的结构体(通常不需要)
memset(&stClient, 0, sizeof(struct sockaddr_un)); // 初始化结构体,将所有字节设置为0
stClient.sun_family = PF_UNIX; // 设置地址家族为Unix域
strcpy(stClient.sun_path, "hanghaiwang"); // 设置客户端套接字文件路径为"hanghaiwang"
unlink(stClient.sun_path); // 如果该文件已存在,则删除它(避免bind失败)
// 尝试将客户端socket绑定到"hanghaiwang"路径(这通常是不必要的)
int ret = bind(iClient, (struct sockaddr *)&stClient, sizeof(struct sockaddr_un));
if (-1 == ret)
{
printf("bind error!-------------\r\n"); // 如果bind失败,打印错误信息
return -1; // 返回-1表示程序异常退出
}
char buf[BUF_SIZE] = {0}; // 定义一个缓冲区,用于存储输入和接收到的数据
socklen_t len = sizeof(struct sockaddr_un); // 设置地址结构的大小
// 3. 无限循环,用于接收用户输入并发送到服务器,然后接收服务器的响应
while (1)
{
memset(buf, 0, BUF_SIZE); // 清空缓冲区,准备接收新的输入
fgets(buf, BUF_SIZE, stdin); // 从标准输入(通常是键盘)读取数据到缓冲区
// 发送到服务器
if (sendto(iClient, buf, strlen(buf), 0, (struct sockaddr *)&stServer, len) > 0)
{
// 注意:发送的数据长度应该是实际输入的数据长度(包括换行符),而不是BUF_SIZE
memset(buf, 0, BUF_SIZE); // 清空缓冲区,准备接收服务器的响应
ret = recvfrom(iClient, buf, BUF_SIZE, 0, (struct sockaddr *)&stServer, &len);
// 接收服务器的响应
printf("recv ok,ret=%d,data:%s\r\n", ret, buf); // 打印接收到的响应和字节数
}
}
// 注意:由于while(1)是一个无限循环,所以这里的return 0;实际上永远不会被执行到
// 但从代码结构完整性考虑,我们仍然保留它
return 0;
}