广播,组播和UNIX域套接字

您所在的位置:网站首页 unix套接字文件属性 广播,组播和UNIX域套接字

广播,组播和UNIX域套接字

2024-07-15 13:01| 来源: 网络整理| 查看: 265

1.广播

1.特点

一对多 仅能使用UDP

2.概念

发送方只有一个接收方则称单播 如果同时发给局域网中的所有主机,成为广播 只有用户数据包(使用UDP协议)套接字才能广播 广播地址

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

3.广播发送步骤

创建用户数据报套接字 缺省创建的套接字不允许广播数据包,需要设置属性setsockopt 接收方地址指定为广播地址 指定端口信息 发送数据包

4.广播接收步骤

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

5.代码

与UDP大同小异 发送方需要将套接字设定为允许广播 int is_use_brc = 1; setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &is_use_brc, sizeof(is_use_brc)); 发送方绑定的IP地址为广播地址 ./sender 192.168.1.255 5002 2.组播

1.概念

单播方式只能有一个接收方 广播方式发送给所有主机.过多的广播会大量占用网络带宽,造成网络风暴,影响正常通信 组播(又称多播)为单播与广播的一种折中方式,只有加入到某个组的主机才能收到数据 多播方式既能发送给多个主机,又能避免像广播那样带来过多负载(即每台主机要到传输层才能判断广播包是否需要处理)

2.组播IP地址段

224.0.0.1~239.255.255.254(中间除去广播IP)

3.组播发送步骤

创建用户数据报套接字 接收方地址设定为组播地址 指定端口信息 发送数据报

4.组播接收步骤

创建用户数据报套接字 加入多播组 绑定本机IP地址与端口(绑定的端口必须与发送方指定的端口相同) 等待数据接收

5.代码

接收方需要加入多播组 /*加入多播组*/ #define MULTICAST_IP "235.10.10.3" struct ip_mreq mreq; bzero(&mreq, sizeof(mreq)); mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_IP);/*多播组的IP地址*/ mreq.imr_interface.s_addr = htonl(INADDR_ANY);/*加入的客服端主机IP地址*/ setsockopt(fd, SOL_SOCKET, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); 发送方绑定地址为多播地址 ./sender 235.10.10.3 5002 3.UNIX域套接字

1.特点

socket同样可以用于本地通信 创建套接字的时候需使用本地协议AF_UNIX/AF_LOCAL socket(AF_LOCAL, SOCK_STREAM, 0); socket(AF_LOCAL, SOCK_DGRAM, 0); 分为流式套接字与用户数据报套接字 与其他进程之间通信方式相比效率更高,使用更方便 常用于前后台进程通信

2.总结

进程之间通信方式有6种:管道,消息队列,共享内存,UNIX域套接字,信号,信号量 按照使用频率排序:消息队列>UNIX域套接字>管道>共享内存(经常需要与信号量一起使用) 按照效率排序:共享内存>UNIX域套接字>管道>消息队列

1.进程之间数据共享:管道,消息队列,共享内存,UNIX域套接字 2.异步通信:信号 3.同步与互斥,做资源保护:信号量

3.代码

大体与网络编程步骤一样,只是在绑定的时候其结构体不同,网络编程为sockaddr_in,域套接字为sockaddr_un #include #define UNIX_PATH_MAX 108 struct sockaddr_un { sa_family_t sun_family;/*AF_UNIX/AF_LOCAL*/ char sun_path[UNIX_PATH_MAX ];/*域套接字文件路径名*/ };

注意:域套接字文件路径名必须事先不存在且一般使用绝对路径,该文件存在于内存中

4.图示

TCP服务器端 TCP客户端 UDP服务器端 UDP客户端

5.示例

客户端 #include "common.h" void tips(char *s) { printf("\n%s unix_domain_file\n\n", s); } int main(int argc, char **argv) { int fd = -1; struct sockaddr_un sin; char buff[BUFSIZ]; int ret = -1/*write函数返回值 */; fd_set rset;/*定义读集合 */ int maxfd = -1;/*保存最大的文件描述符 */ struct timeval tout;/*超时时间结构体 */ /*创建socket */ if(argc != 2) { tips(argv[0]); exit(-1); } if((fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(-1); } /*判断UNIX_DOMAIN_FILE文件是否存在且可写*/ if(access(UNIX_DOMAIN_FILE, F_OK|W_OK) < 0) { puts("UNIX_DOMAIN_FILE is unkonwn"); exit(-1); } /*结构体成员清零 */ bzero(&sin, sizeof(sin)); /*填充结构体 */ sin.sun_family = AF_LOCAL; strncpy(sin.sun_path, UNIX_DOMAIN_FILE, strlen(UNIX_DOMAIN_FILE)); /*连接服务器 */ if(connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror("connect"); exit(-1); } puts("Unix domain client init ok..."); while (1) { /*读集合清零 */ FD_ZERO(&rset); /*加入进程默认打开的标准键盘输入fd */ FD_SET(0, &rset); /*加入客户端与服务器通信的fd */ FD_SET(fd, &rset); maxfd = fd; tout.tv_sec = 5;/*超时时间为5秒 */ tout.tv_usec = 0; select(maxfd + 1, &rset, NULL, NULL, &tout); /*代表标准键盘有输入 */ if(FD_ISSET(0, &rset)) { bzero(buff, BUFSIZ); /*-1防止数组下标越界 */ do { ret = read(0, buff, BUFSIZ - 1); } while (ret < 0 && EINTR == errno); if(ret < 0) { perror("read from keyboard"); continue; } /*如果ret=0表示没有从键盘上读到数据 */ if(!ret) { continue; } if(write(fd, buff, strlen(buff)) < 0) { perror("write to socket"); continue; } if(strcmp(buff, QUIT_STR) == 0) { printf("Client is exting...\n"); break; } } /*代表有服务器的数据到达 */ if(FD_ISSET(fd, &rset)) { bzero(buff, BUFSIZ); /*-1防止数组下标越界 */ do { ret = read(fd, buff, BUFSIZ - 1); } while (ret < 0 && EINTR == errno); if(ret < 0) { perror("read from server"); continue; } /*如果ret=0表示服务器关闭 */ if(!ret) { break; } printf("recv from server:%s\n", buff); /*此处存在BUG,待修复 */ if(strlen(buff) > strlen(SERV_RESP_STR)) { if(strcmp(buff + strlen(SERV_RESP_STR), QUIT_STR) == 0) { printf("sender is exting...\n"); break; } } } } close(fd); return 0; } 服务器 #include "common.h" void client_fork(void *arg); /*子进程结束信号处理函数 */ void sig_child_handle(int signo) { /*回收子进程 */ if(SIGCHLD == signo) { waitpid(-1, NULL, WNOHANG); } } int main(void) { pid_t pid; int fd = -1; int newfd = -1; int b_reuse = 1; struct sockaddr_un sun;/*定义本地通信套接字*/ signal(SIGCHLD, sig_child_handle); /*创建本地域套接字 */ if((fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(-1); } /*允许绑定地址快速重用 */ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int)); /*结构体成员清零 */ bzero(&sun, sizeof(sun)); /*填充结构体 */ sun.sun_family = AF_LOCAL; /*如果UNIX指定文件存在则删除该文件*/ if(!access(UNIX_DOMAIN_FILE, F_OK)) { unlink(UNIX_DOMAIN_FILE); } strncpy(sun.sun_path, UNIX_DOMAIN_FILE, strlen(UNIX_DOMAIN_FILE)); /*绑定socket */ if(bind(fd, (struct sockaddr *)&sun, sizeof(sun)) < 0) { perror("bind"); exit(-1); } /*主动套接字转被动套接字 */ if(listen(fd, BACKLOG) < 0) { perror("listen"); exit(-1); } puts("Server staring ok"); while(1) { /*阻塞等待客户端连接请求并保存客户端信息 */ if((newfd = accept(fd, NULL, NULL)) < 0) { perror("accept"); break; } /*创建子进程,用于处理客户端数据 */ if((pid = fork()) < 0) { perror("fork"); break; } /*子进程 */ if(0 == pid) { close(fd); /*客户端IP地址网络字节序转本地字节序 */ client_fork(&newfd); return 0; } /*父进程 */ else { close(newfd); } } close(fd); return 0; } void client_fork(void * arg) { char buf[BUFSIZ]; char resp_buf[BUFSIZ + 10]; int ret = -1;/*read函数返回值 */ int newfd = *(int *)arg; printf("process newfd = %d\n", newfd); while(1) { /*与newfd进行读写 */ bzero(buf, BUFSIZ); /*判断读函数是否出错 */ do { ret = read(newfd, buf, BUFSIZ - 1); } while (ret < 0 && EINTR == errno); if(ret < 0) { perror("read"); exit(-1); } if(0 == ret) { break; } printf("Unix domain service receive data: %s\n", buf); bzero(resp_buf, BUFSIZ + 10); strncpy(resp_buf, SERV_RESP_STR, strlen(SERV_RESP_STR)); strcat(resp_buf, buf); do { ret = write(newfd, resp_buf, strlen(resp_buf)); } while (ret < 0 && EINTR == errno); if(strcmp(buf, QUIT_STR) == 0) { printf("Client is exting...\n"); break; } } close(newfd); }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3