网络编程扩展 广播 多播 unix套接字

广播编程

什么是广播

前面介绍的数据包发送方式只有一个接受方,称为单播如果同时发给局域网中的所有主机,称为广播只有用户数据报(使用UDP协议)套接字才能广播

广播地址

以192.168.1.0 (255.255.255.0) 网段为例,最大的主机地址 192.168.1.255 代表该网段的广播地址发到该地址的数据包被所有的主机接收255.255.255.255在所有网段中都代表广播地址

广播的编程思路

同之前的单播一样,广播也是需要发送方和接收方的,具体流程如下:

广播发送 发送方相当于client

  1. 创建用户数据报套接字
fd = socket(AF_INET,SOCK_DGRAM,0);  //基于IPv4协议的UDP套接字
  1. 缺省创建的套接字不允许广播数据包,需要设置属性,setsockopt可以设置套接字属性
int ab_aben = 1;
setsockopt(fd,SOL_SOCKET,SO_BROADCAST,&ab_aben,sizeof(int)); //允许发送广播数据包
  1. 接收方地址指定为广播地址 xxx.xxx.xxx.255
  2. 指定端口信息
  3. 发送数据包

广播接收 接收方相当于server

  1. 创建用户数据报套接字
  2. 绑定本机IP地址和端口 ,绑定的端口必须和发送方指定的端口相同
  3. 等待接收数据

发送方范例:

#include <cstdio>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>

#define DEBUG 0

void usage(char* s) {
    printf("\nThis is udp demo!\n");
    printf("\nUsage:\n\t %s serv_ip serv_port", s);
    printf("\n\t serv_ip: udp server ip address");
    printf("\n\t serv_port: udp server port(serv_port > 5000)\n\n");
}

int main(int argc, char* argv[])
{
    int fd = -1;
    int result = 0;
    int SERV_PORT = -1;
    char* SERV_IP_ADDR = NULL;
    struct sockaddr_in mysockaddr;
    char MESSAGE[] = "hELLo wOLd!!!\n";
    char botton[64] = {0};
#if DEBUG
    SERV_PORT = 5050;
    SERV_IP_ADDR = "192.168.0.158";
#else
    if (argc != 3) {
        usage(argv[0]);
        return -1;
    }

    SERV_PORT = atoi(argv[2]);
    if (SERV_PORT <= 5000) {
        usage(argv[0]);
        return -1;
    }
    SERV_IP_ADDR = argv[1];
#endif
    /* 1. 创建socket fd */
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        perror("socket");
        return -1;
    }
    /*2.连接服务器 写入数据 */

    /*2.1 填充struct sockaddr_in结构体变量 */
    bzero((void*)&mysockaddr, sizeof(mysockaddr));
    mysockaddr.sin_family = AF_INET;
    mysockaddr.sin_port = htons(SERV_PORT); //网络字节序的端口号
#if 0    
    mysockaddr.sin_addr.s_addr = inet_addr(SERV_IP_ADDR);
#else
    result = inet_pton(AF_INET, SERV_IP_ADDR, (void*)&mysockaddr.sin_addr);
    if (result != 1) {
        perror("inet_pton");
        return -1;
    }
#endif
    /*2.2  读写数据*/
    printf("Client staring...OK!\n");
    struct sockaddr_in clientscokaddr;
    socklen_t clientaddrlen;
    clientaddrlen = sizeof(clientscokaddr);

    while (1) {
        do {
            result = sendto(fd, MESSAGE, strlen(MESSAGE), 0, (struct sockaddr*)&mysockaddr, sizeof(mysockaddr));
        } while (result < 0 && EINTR == errno);   //判断是否阻塞了     
        if (result < 0) {
            perror("connect");
            break;
        }
        
        sleep(1);

        bzero((void*)botton, 64);
        bzero((void*)&clientscokaddr, clientaddrlen);
        
        do {
            result = recvfrom(fd, botton, 63, MSG_DONTWAIT, (struct sockaddr*)&clientscokaddr, &clientaddrlen);
        } while (result < 0 && EINTR == errno);
        printf("message is:%s\n", botton);
        
    }

    close(fd);
    return 0;
}

接收方范例:

#include <cstdio>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>

#define SERV_PORT 5050
#define SERV_IP_ADDR "192.168.0.158"

int fun_process(int fd,char* botton,sockaddr_in clientscokaddr, socklen_t clientaddrlen);
void handler(int signo) {   //自动回收子进程 防止僵尸进程

    if (signo == SIGCHLD)
    {
        printf("Recall SIGINT\n");
        waitpid(-1, NULL, WNOHANG);
    }
}

int main()
{
    int fd = -1;
    int result = 0;
    pid_t pid;
    struct sockaddr_in mysockaddr;
    struct sockaddr_in clientscokaddr;
    socklen_t clientaddrlen;
    char botton[64];

    /* 1. 创建socket fd */
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        perror("socket");
        return -1;
    }

    /*优化4: 允许绑定地址快速重用 */
    int b_reuse = 1;
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));

    /*2. 绑定 */
    /*2.1 填充struct sockaddr_in结构体变量 */
    bzero((void*)&mysockaddr, sizeof(mysockaddr));
    mysockaddr.sin_family = AF_INET;
    mysockaddr.sin_port = htons(SERV_PORT);//网络字节序的端口号
    mysockaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    /*2.2 绑定 */
    result = bind(fd, (struct sockaddr*)&mysockaddr, sizeof(mysockaddr));
    if (result != 0) {
        perror("bind");
        return -1;
    }

    /*3. 调用recvfrom 接收客户端发来的信息 */
    /*优化2:通过程序获取刚建立连接的socket的客户端的IP地址和端口号*/
    clientaddrlen = sizeof(clientscokaddr);
    signal(SIGCHLD, handler);

    while (1) {
        bzero((void*)botton, 64);
        bzero((void*)&clientscokaddr, clientaddrlen);
       
        do {
            result = recvfrom(fd, botton, 63, 0, (struct sockaddr*)&clientscokaddr, &clientaddrlen);
        } while (result < 0 && EINTR == errno);

        if (-1 == result) {
            perror("recvfrom");
            break;
        }
        pid = fork();
        if (pid < 0) {
            perror("fork");
            break;
        }
        else if (0 == pid) {
            result = fun_process(fd, botton,clientscokaddr, clientaddrlen);
            close(fd);
            return result;
        }     
    }

    close(fd);
    return 0;
}

int fun_process(int fd, char* botton,sockaddr_in clientscokaddr, socklen_t clientaddrlen) {
    char ipv4_addr[16];
    int result;
    char botton_re[64] = "recv success!";
    printf("23333\n");
    if (!inet_ntop(AF_INET, (void*)&clientscokaddr.sin_addr, ipv4_addr, clientaddrlen)) {
        perror("inet_ntop");
        return -1;
    }

    printf("Clinet(%s:%d) is connected!\n", ipv4_addr, ntohs(clientscokaddr.sin_port));

    printf("message is:%s\n", botton);
    do {
        result = sendto(fd, botton_re, strlen(botton_re), 0, (struct sockaddr*)&clientscokaddr, sizeof(clientscokaddr));
    } while (result < 0 && EINTR == errno);   //判断是否阻塞了     
    if (result < 0) {
        perror("connect");
        return -1;
    }
    
    return 0;
}

效果图

组播

什么是组播

主机之间“一对一组”的通讯模式,也就是加入了同一个组的主机可以接受到此组内的所有数据,网络中的交换机和路由器只向有需求者复制并转发其所需数据。主机可以向路由器请求加入或退出某个组,网络中的路由器和交换机有选择的复制并传输数据,即只将组内数据传输给那些加入组的主机。这样既能一次将数据传输给多个有需要(加入组)的主机,又能保证不影响其他不需要(未加入组)的主机的其他通讯。

组播的特点及地址区间

组播是一个发送方,多个接收方,接收方必须是加入多播组的成员。
组播的IP地址:224.0.0.1 – 239.255.255.254 (中间除掉广播)239.0.0.0—239.255.255.255是私有地址,供各个内部网在内部使用
组播必须基于UDP的编程方法

组播的编程思路:

组播的编程分发送端和接收端两种,具体思路如下:

组播的发送 相当于 UDP 的client端

  1. 创建用户数据报套接字
fd = socket(AF_INET,SOCK_DGRAM,0);  //基于IPv4协议的UDP套接字
  1. 接收方地址指定为组播地址
    239.0.0.0—239.255.255.255是私有地址,供各个内部网在内部使用

  2. 指定端口信息
    5050

  3. 发送数据包
    sendto()

组播的接收 相当于 UDP 的server端

  1. 创建用户数据报套接字
fd = socket(AF_INET,SOCK_DGRAM,0);  //基于IPv4协议的UDP套接字
  1. 加入多播组
struct ip_mreq{
     struct  in_addr  imr_multiaddr;
     struct  in_addr  imr_interface;
};

struct  ip_mreq  mreq;
bzero(&mreq, sizeof(mreq));
mreq.imr_multiaddr.s_addr = inet_addr(235.10.10.3);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);

setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,  
                  sizeof(mreq));

  1. 绑定本机IP地址和端口 ,绑定的端口必须和发送方指定的端口相同
    5050

  2. 等待接收数据
    recvfrom();

组播发送端示例代码

#include <cstdio>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>

#define DEBUG 0

void usage(char* s) {
    printf("\nThis is udp demo!\n");
    printf("\nUsage:\n\t %s serv_ip serv_port", s);
    printf("\n\t serv_ip: udp server ip address");
    printf("\n\t serv_port: udp server port(serv_port > 5000)\n\n");
}

int main(int argc, char* argv[])
{
    int fd = -1;
    int result = 0;
    int SERV_PORT = -1;
    char* SERV_IP_ADDR = NULL;
    struct sockaddr_in mysockaddr;
    char MESSAGE[] = "hELLo wOLd!!!\n";
    char botton[64] = {0};
#if DEBUG
    SERV_PORT = 5050;
    SERV_IP_ADDR = "192.168.0.158";
#else
    if (argc != 3) {
        usage(argv[0]);
        return -1;
    }

    SERV_PORT = atoi(argv[2]);
    if (SERV_PORT <= 5000) {
        usage(argv[0]);
        return -1;
    }
    SERV_IP_ADDR = argv[1];
#endif
    /* 1. 创建socket fd */
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        perror("socket");
        return -1;
    }
    /*2.连接服务器 写入数据 */

    /*2.1 填充struct sockaddr_in结构体变量 */
    bzero((void*)&mysockaddr, sizeof(mysockaddr));
    mysockaddr.sin_family = AF_INET;
    mysockaddr.sin_port = htons(SERV_PORT); //网络字节序的端口号
#if 0    
    mysockaddr.sin_addr.s_addr = inet_addr(SERV_IP_ADDR);
#else
    result = inet_pton(AF_INET, SERV_IP_ADDR, (void*)&mysockaddr.sin_addr);
    if (result != 1) {
        perror("inet_pton");
        return -1;
    }
#endif
    /*2.2  读写数据*/
    printf("Client staring...OK!\n");
    struct sockaddr_in clientscokaddr;
    socklen_t clientaddrlen;
    clientaddrlen = sizeof(clientscokaddr);

    while (1) {
        do {
            result = sendto(fd, MESSAGE, strlen(MESSAGE), 0, (struct sockaddr*)&mysockaddr, sizeof(mysockaddr));
        } while (result < 0 && EINTR == errno);   //判断是否阻塞了     
        if (result < 0) {
            perror("connect");
            break;
        }
        
        sleep(1);

        bzero((void*)botton, 64);
        bzero((void*)&clientscokaddr, clientaddrlen);
        
        do {
            result = recvfrom(fd, botton, 63, MSG_DONTWAIT, (struct sockaddr*)&clientscokaddr, &clientaddrlen);
        } while (result < 0 && EINTR == errno);
        printf("message is:%s\n", botton);
        
    }

    close(fd);
    return 0;
}

组播接收端示例代码

#include <cstdio>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>

#define SERV_PORT 5050
#define SERV_IP_ADDR "239.0.0.10"

int fun_process(int fd,char* botton,sockaddr_in clientscokaddr, socklen_t clientaddrlen);
void handler(int signo) {   //自动回收子进程 防止僵尸进程

    if (signo == SIGCHLD)
    {
        printf("Recall SIGINT\n");
        waitpid(-1, NULL, WNOHANG);
    }
}

int main()
{
    int fd = -1;
    int result = 0;
    pid_t pid;
    struct sockaddr_in mysockaddr;
    struct sockaddr_in clientscokaddr;
    socklen_t clientaddrlen;
    char botton[64];

    /* 1. 创建socket fd */
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        perror("socket");
        return -1;
    }

    /*优化4: 允许绑定地址快速重用 */
    int b_reuse = 1;
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));
	/* 设置组播 */
	struct ip_mreq mreq;
	bzero(&mreq,sizeof(struct ip_mreq));
	mreq.imr_multiaddr.s_addr = inet_addr("239.0.0.10");
	mreq.imr_interface.s_addr = htonl(INADDR_ANY);
	setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));

    /*2. 绑定 */
    /*2.1 填充struct sockaddr_in结构体变量 */
    bzero((void*)&mysockaddr, sizeof(mysockaddr));
    mysockaddr.sin_family = AF_INET;
    mysockaddr.sin_port = htons(SERV_PORT);//网络字节序的端口号
    mysockaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    /*2.2 绑定 */
    result = bind(fd, (struct sockaddr*)&mysockaddr, sizeof(mysockaddr));
    if (result != 0) {
        perror("bind");
        return -1;
    }

    /*3. 调用recvfrom 接收客户端发来的信息 */
    /*优化2:通过程序获取刚建立连接的socket的客户端的IP地址和端口号*/
    clientaddrlen = sizeof(clientscokaddr);
    signal(SIGCHLD, handler);

    while (1) {
        bzero((void*)botton, 64);
        bzero((void*)&clientscokaddr, clientaddrlen);
       
        do {
            result = recvfrom(fd, botton, 63, 0, (struct sockaddr*)&clientscokaddr, &clientaddrlen);
        } while (result < 0 && EINTR == errno);

        if (-1 == result) {
            perror("recvfrom");
            break;
        }
        pid = fork();
        if (pid < 0) {
            perror("fork");
            break;
        }
        else if (0 == pid) {
            result = fun_process(fd, botton,clientscokaddr, clientaddrlen);
            close(fd);
            return result;
        }     
    }

    close(fd);
    return 0;
}

int fun_process(int fd, char* botton,sockaddr_in clientscokaddr, socklen_t clientaddrlen) {
    char ipv4_addr[16];
    int result;
    char botton_re[64] = "recv success!";
    printf("23333\n");
    if (!inet_ntop(AF_INET, (void*)&clientscokaddr.sin_addr, ipv4_addr, clientaddrlen)) {
        perror("inet_ntop");
        return -1;
    }

    printf("Clinet(%s:%d) is connected!\n", ipv4_addr, ntohs(clientscokaddr.sin_port));

    printf("message is:%s\n", botton);
    do {
        result = sendto(fd, botton_re, strlen(botton_re), 0, (struct sockaddr*)&clientscokaddr, sizeof(clientscokaddr));
    } while (result < 0 && EINTR == errno);   //判断是否阻塞了     
    if (result < 0) {
        perror("connect");
        return -1;
    }
    
    return 0;
}

结果展示:


UNIX域(流式)套接字

socket同样可以用于本地通信

为什么选择UNIX域套接字

进程间通信:

  1. 进程间的数据共享
    共享内存,管道,消息队列,,unix域套接字
    易用性:消息队列 > unix域套接字 > 管道 > 共享内存(经常需要和信号量一起用)
    效率: 共享内存 > unix域套接字 > 管道 > 消息队列
    常用: 共享内存 unix域套接字

  2. 异步通信:
    信号

  3. 同步和互斥(做资源保护):
    信号量

unix域套接字下的 socket() 函数

/* 创建套接字时使用本地协议PF_UNIX(或PF_LOCAL)。 */
  socket(AF_LOCAL, SOCK_STREAM, 0); //AF_LOCAL 可替换成 AF_UNIX
  socket(AF_LOCAL, SOCK_DGRAM, 0);  //同上

UNIX域套接字分为 流式套接字 和 用户数据报套接字, 和其他进程间通信方式相比使用方便、效率更高,常用于前后台进程通信

SYNOPSIS

       #include <sys/socket.h>
       sockfd = socket(int socket_family, int socket_type, int protocol);

socket_family:填AF_LOCAL或者AF_UNIX均可
socket_type:填SOCK_STREAM(流式)SOCK_DGRAM(报文)视情况而定
protocol:填0

本地地址结构

struct sockaddr_un        //  <sys/un.h>
{
    sa_family_t  sun_family;
    char  sun_path[108];         // 套接字文件的路径
};

填充地址结构

struct sockaddr_un myaddr;
bzero(&myaddr,  sizeof(myaddr));
myaddr.sun_family = AF_UNIX;    
strcpy(myaddr.sun_path,"/tmp/mysocket");

UNIX流式套接字 服务器端 编程流程

UNIX流式套接字 客户端 编程流程

unix套接字 通信示意图

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

struct sockaddr_un {
               sa_family_t sun_family;               /* AF_UNIX */  
               char        sun_path[108];            /* Pathname */
           };

The sun_family field always contains AF_UNIX.  On Linux, sun_path is 108 bytes in size; 
翻译:sun_family 通常值为 AF_UNIX (或者AF_LOCAL),sun_path的值一般值是96~108之间,linux下是108.
注意:sun_path 是unix域套接的文件路径名,该文件为在内存中的文件(使用ls -a可以查看到其特殊的文件属性),
    该文件有两点要求:1.必须事先不存在 2.地址格式一般写作绝对路径。 

UNIX流式套接字 server code 示例:

#include <cstdio>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>  
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/un.h>

#define SERV_PORT 5050
#define SERV_IP_ADDR "192.168.0.158"
#define FILE_ADDR "/tmp/mysocket"

int func_recall(int arg);
char botton[64];

int main()
{
    int fd = -1;
    int fdbox[1024], fd_count = 0;;
    int result = 0, i = 0;
    struct sockaddr_un unaddr;
    struct sockaddr_un clientscokaddr;

    /* 1. 创建socket fd */
    fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (fd < 0) {
        perror("socket");
        return -1;
    }

    /*优化4: 允许绑定地址快速重用 */
    int b_reuse = 1;
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));

    /*2. 绑定 */
    /*2.1 填充struct sockaddr_un构体变量 */
    bzero((void*)&unaddr, sizeof(unaddr));
    unaddr.sun_family = AF_UNIX;
    strcpy(unaddr.sun_path,FILE_ADDR);//网络字节序的端口号

    /*2.2 绑定 */
	result = access(FILE_ADDR, F_OK);//测试文件是否存在 
	if(!result){
		result = unlink(FILE_ADDR);  //如果存在则删除
		if(result){
			perror("unlink");
			return -1;
		}
	}
    result = bind(fd, (struct sockaddr*)&unaddr, sizeof(unaddr));
    if (result != 0) {
        perror("bind");
        return -1;
    }

    /*3. 调用listen()把主动套接字变成被动套接字 */
    result = listen(fd, 5);
    if (result != 0) {
        perror("listen");
        return -1;
    }

    /*4. 等待客户端连接请求 */

    /* 优化3. 采用多路复用的方式防止阻塞*/
    fd_set rset;
    int fd1;
    fd1 = fd+1;
    fd_count = 1;
    fdbox[0] = fd;

    struct timeval tm;  //非阻塞状态 采用轮询方式
    tm.tv_sec = 0;
    tm.tv_usec = 0;

    int fd_client;
    while(1){
        //清零rset
        FD_ZERO(&rset);
        //置位rset 标识出要监控的文件标识符
        for (i = 0; i < fd_count; i++) {
            FD_SET(fdbox[i], &rset);
        }
        //查询是否有标识符被激活
        result = select(fd1, &rset, NULL, NULL, &tm);

        if (result < 0) {
            perror("select");
            return 0;
        }
        else if (result > 0) {
            //socket fd被激活 接收到新的客户端连接请求
            if (FD_ISSET(fdbox[0], &rset)) {
                bzero((void*)&clientscokaddr, sizeof(clientscokaddr));
                fd_client = accept(fd, NULL, NULL); 		//本地文件 不关心从何而来
                if (-1 == result) {
                    perror("accpet");
                    return 0;
                }

                printf("unix socket is connected!\n");

                //将新建立连接的fd写入数组 以供select调用
                fdbox[fd_count] = fd_client;
                fd_count++;
                fd1++;
            }         
             
            //客户端fd被激活 处理客户端发来信息 
            for (i = 1; i < fd_count; i++) {
                if (FD_ISSET(fdbox[i], &rset)){
                    result = func_recall(fdbox[i]);
                    if (result != 0) {
                        printf("error:func_recall");
                        return -1;
                    }
                }      
            }
            
        }

        sleep(1);
                    
    }

    close(fd);
    
    return 0;
}

int func_recall(int arg) {
    int result = 0;
    int newfd = arg;
    char Quit[] = "quit";
    printf("handler thread: newfd =%d\n", newfd);
    //..和newfd进行数据读写
    char buf[BUFSIZ];
   
    bzero(buf, BUFSIZ);

    do {
        result = read(newfd, buf, BUFSIZ - 1);
    } while (result < 0 && EINTR == errno);

    if (result < 0) {
        perror("read");
        return -1;
    }

    if (!result)
        return 0;

    if (!strcmp(Quit, buf)) {
        printf("client quit...close socket.\n ");
        close(newfd);
    }
    else {
        printf("message is:%s\n", buf);
    }

    return 0;
}

UNIX流式套接字 client code 示例:

#include <cstdio>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <sys/un.h>

#define SERV_PORT 5050
#define SERV_IP_ADDR "192.168.0.158"
#define FILE_ADDR "/tmp/mysocket"
int main()
{
    int fd = -1;
    int result = 0;
    struct sockaddr_un mysockaddr;
    char MESSAGE[] = "hELLo wOLd...\n";

    fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (fd < 0) {
        perror("socket");
        return -1;
    }

    bzero((void*)&mysockaddr, sizeof(mysockaddr));
    mysockaddr.sun_family = AF_LOCAL;
    strcpy(mysockaddr.sun_path,FILE_ADDR);

	/* 确保UNIX_DOMAIN_FILE要先存在,并且可读写 */
	result = access(FILE_ADDR,F_OK|R_OK|W_OK);
	if(result){
		perror("access");
		return -1;
	}

    result = connect(fd, (struct sockaddr*)&mysockaddr, sizeof(mysockaddr));
    if (result != 0) {
        perror("connect");
        return -1;
    }
    printf("Unix client staring...OK!\n");

    while (1) {
        do {
            result = write(fd, (void*)MESSAGE, sizeof(MESSAGE));
        } while (result < 0 && EINTR == errno);         
        sleep(10);
    }

    close(fd);
    return 0;
}

UNIX流式套接字测试图


UNIX域用户数据报套接字 服务器端 编程流程

UNIX域用户数据报套接字 客户端 编程流程

UNIX域用户数据报套接字

UNIX域用户数据报套接字 server code 示例:

UNIX域用户数据报套接字 client code 示例:

延申

组播详解:https://blog.csdn.net/kkfloat/article/details/38252291?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allfirst_rank_v2~rank_v25-1-38252291.nonecase&utm_term=%E7%BB%84%E6%92%AD%E8%B7%AF%E7%94%B1%E9%85%8D%E7%BD%AE