每次只有两个实体相互通信,发送端和接收端都是唯一确定的。
广播地址: 主机号最大的地址;
以192.168.1.0 (255.255.255.0) 网段为例,最大的主机地址192.168.1.255代表该网段的广播地址
(同一局域网内的主机都会接收到,如果其他主机没有加入广播站,就会将消息丢弃)
setsockopt 设置套接字的属性
- 头文件:
- #include
- #include
- #include
-
- 原型: int setsockopt(int sockfd,int level,int optname,\
- void *optval,socklen_t optlen)
- 功能: 获得/设置套接字属性
- 参数:
- sockfd:套接字描述符
- level:协议层
- optname:选项名
- optval:选项值
- optlen:选项值大小
-
- 返回值: 成功 0 失败-1
-
1)广播的发送端流程 ---》类似于UDP的客户端
a。IP (192.168.50.255/255.255.255.255)
b。端口号
1. 创建用户数据报套接字;
sockfd = socket(AF_INET,SOCK_DGRAM,0);
2.setsockopt可以设置套接字属性,先设定该套接字允许发送广播
- int optval = 1;
- // SOL_SOCKET 传输层 SO_BROADCAST 允许发送广播
- setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&optval,sizeo(optval));
- struct sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(atoi(argv[2]));
- addr.sin_addr.s_addr = inet_addr(argv[1]);
4. 发送数据包
- sendto(sockfd,buf,sizeof(buf),0,\
- (struct sockaddr*)&addr,sizeof(addr));
发送者需要借助 setsockopt 开通广播权限:
./client:

- /*客户端创建代码 */
- #include <stdio.h>
- #include <sys/types.h> /* See NOTES */
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/ip.h> /* superset of previous */
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
-
- int main(int argc, char const *argv[])
- {
- if(argc<3)
- {
- printf("plase input
" ); - }
- //1.创建套接字,用于链接
- int sockfd;
- sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sockfd < 0)
- {
- perror("socket err");
- return -1;
- }
- printf("sockfd:%d\n", sockfd);
- //2.判断是否允许广播
- int broad;
- socklen_t lenth = sizeof(broad);//确定broad长度
- getsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broad, &lenth); //获取sockfd属性
- printf("%d\n",broad);
- //设置允许广播
- broad=1;
- setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broad, lenth);
- printf("设置网络成功\n");
- //2.填充结构体
- struct sockaddr_in saddr;
- saddr.sin_family = AF_INET;
- saddr.sin_port = htons(atoi(argv[1]));
- saddr.sin_addr.s_addr = inet_addr("192.168.50.255");
- socklen_t len = sizeof(saddr); //结构体大小
- char buf[128] = {0};
- int ret;
- while (1)
- {
- //发送信息
- printf("client:");
- fgets(buf, sizeof(buf), stdin); //从终端获取内容存放到数组中
- if (strncmp(buf, "quit", 4) == 0) //输入quit退出客户端
- {
- break;
- }
- if (buf[strlen(buf)] == '\0')
- {
- buf[strlen(buf) - 1] = '\0';
- }
- sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&saddr, len);
- }
- close(sockfd);
- return 0;
- }
-
2)广播的接收端流程 -----》类似于UDP服务器
基本无需改动
sockfd = socket(AF_INET,SOCK_DGRAM,0);
2. 绑定IP地址(广播IP或0.0.0.0)和端口
广播的接收者需要加入 广播站
- struct sockaddr_in saddr,caddr;
- saddr.sin_family = AF_INET;
- saddr.sin_port = htons(atoi(argv[2]));
- saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
- //广播地址或0.0.0.0
- //0.0.0.0 是一个特殊的IP地址,用于表示服务器端将监听所有可用的网络接口
- // 而不仅仅是IP地址,广播地址也会监听。
-
- socklen_t len = sizeof(caddr);
- bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
3. 等待接收数据
- recvfrom(sockfd,buf,sizeof(buf),0,\
- (struct sockaddr *)&caddr,&len);
- /*服务器创建代码 */
- #include <stdio.h>
- #include <sys/types.h> /* See NOTES */
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/ip.h> /* superset of previous */
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
-
- int main(int argc, char const *argv[])
- {
- if (argc < 2)
- {
- printf("plase input
\n" ); - return -1;
- }
- //1.创建套接字,用于链接
- int sockfd;
- sockfd = socket(AF_INET,SOCK_DGRAM, 0);
- if (sockfd < 0)
- {
- perror("socket err");
- return -1;
- }
- printf("sockfd:%d\n", sockfd);
- //2.绑定 ip+port 填充结构体
- struct sockaddr_in saddr;
- saddr.sin_family = AF_INET;
- saddr.sin_port = htons(atoi(argv[1]));
- saddr.sin_addr.s_addr = inet_addr("192.168.50.255");
- socklen_t len = sizeof(saddr); //结构体大小
- //bind绑定ip和端口
- if (bind(sockfd, (struct sockaddr *)&saddr, len) < 0)
- {
- perror("bind err");
- return -1;
- }
- printf("bind success\n");
- char buf[128] = {0};
- while (1)
- {
- //接收信息
- if (recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&saddr, &len) < 0)
- {
- perror("recvfrom err");
- return -1;
- }
- printf("client ip:%s ,port:%d buf:%s\n", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port),buf);
- // //发送信息
- // printf("server:");
- // fgets(buf, sizeof(buf), stdin); //从终端获取内容存放到数组中
- // if (strncmp(buf, "quit", 4) == 0) //输入quit退出客户端
- // {
- // break;
- // }
- // if (buf[strlen(buf)] == '\0')
- // {
- // buf[strlen(buf) - 1] = '\0';
- // }
- // sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&saddr, len);
- }
- close(sockfd);
- return 0;
- }
-
广播方式发给所有的主机,过多的广播会大量的占用网络带宽,造成广播风暴,影响正常的通信;
224.10.10.10(相当于组名)
。单播方式只能发给一个接收方
。 组播是一个人发送,加入到多播组的主机接收数据
。 多播方式既可以发给多个主机,又能避免像广播一样造成过多的负载:
IP的二级划分中 D类IP:
第一字节的前四位固定为 1110
D类IP : 224.0.0.1 - 239.255.255.255
224.10.10.10
1)组播的发送端流程 ---》类似于UDP的客户端
1. 创建用户数据报套接字;
sockfd = socket(AF_INET,SOCK_DGRAM,0);
2. 指定接收方地址指定为组播地址 224.0.0.10 (224.0.0.1 - 239.255.255.255都可以) 并指定接收端端口信息
- //2. 填充结构体: 组播ip 和 端口
- struct sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(atoi(argv[2]));
- addr.sin_addr.s_addr = inet_addr(argv[1]); //组播的IP
3. 发送数据包
sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&addr,sizeof(addr));
- /*客户端创建代码 */
- #include <stdio.h>
- #include <sys/types.h> /* See NOTES */
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/ip.h> /* superset of previous */
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
-
- int main(int argc, char const *argv[])
- {
- if(argc<3)
- {
- printf("plase input
" ); - }
- //1.创建套接字,用于链接
- int sockfd;
- sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sockfd < 0)
- {
- perror("socket err");
- return -1;
- }
- printf("sockfd:%d\n", sockfd);
- // //2.判断是否允许广播
- // int broad;
- // socklen_t lenth = sizeof(broad);//确定broad长度
- // getsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broad, &lenth); //获取sockfd属性
- // printf("%d\n",broad);
- // //设置允许广播
- // broad=1;
- // setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broad, lenth);
- // printf("设置网络成功\n");
- //2.填充结构体
- struct sockaddr_in saddr;
- saddr.sin_family = AF_INET;
- saddr.sin_port = htons(atoi(argv[2]));
- saddr.sin_addr.s_addr = inet_addr(argv[1]);//组播ip
- socklen_t len = sizeof(saddr); //结构体大小
- char buf[128] = {0};
- int ret;
- while (1)
- {
- //发送信息
- printf("client:");
- fgets(buf, sizeof(buf), stdin); //从终端获取内容存放到数组中
- if (strncmp(buf, "quit", 4) == 0) //输入quit退出客户端
- {
- break;
- }
- if (buf[strlen(buf)] == '\0')
- {
- buf[strlen(buf) - 1] = '\0';
- }
- sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&saddr, len);
- }
- close(sockfd);
- return 0;
- }
-
1)组播的接收端流程 ---》类似于UDP的服务器
1)组播的接收端流程 ---》类似于UDP的服务器
- struct ip_mreq
- {
- struct in_addr imr_multiaddr; /* 指定多播组IP */
- struct in_addr imr_interface; /* 本地网卡地址,通常指定为 INADDR_ANY--0.0.0.0*/};
- }
- struct ip_mreq mreq;
- //bzero(&mreq, sizeof(mreq));
- mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.1");
- mreq.imr_interface.s_addr = INADDR_ANY;
- setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
1、创建用户数据报套接字;
sockfd = socket(AF_INET,SOCK_DGRAM,0);
2. 加入多播组 : 只有接收者加入多播组 (广播是发送者需要设置广播属性,组播是接收者加入多播组)
- //2.将主机假如多播组
- struct ip_mreq mreq; //组播的结构体变量
- mreq.imr_multiaddr.s_addr = inet_addr(argv[1]); //组IP
- mreq.imr_interface.s_addr = inet_addr("0.0.0.0"); //本地IP加入到上面的多播组
- // 将本地IP 加入到多播组 setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
3. 绑定组播IP地址(绑定组播IP或0.0.0.0)和端口
- //3. 填充结构体: 绑定组播ip和端口
- struct sockaddr_in saddr,caddr;
- saddr.sin_family = AF_INET;
- saddr.sin_port = htons(atoi(argv[2]));
- saddr.sin_addr.s_addr = inet_addr("0.0.0.0"); //组IP
4. 接收数据包
recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&caddr,&len);
- /*服务器创建代码 */
- #include <stdio.h>
- #include <sys/types.h> /* See NOTES */
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/ip.h> /* superset of previous */
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
-
- int main(int argc, char const *argv[])
- {
- if (argc < 3)
- {
- printf("plase input
\n" ); - return -1;
- }
- //1.创建套接字,用于链接
- int sockfd;
- sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sockfd < 0)
- {
- perror("socket err");
- return -1;
- }
- printf("sockfd:%d\n", sockfd);
-
- //设置接收组播
- struct ip_mreq group;
- group.imr_multiaddr.s_addr = inet_addr(argv[1]); //组IP
- group.imr_interface.s_addr = inet_addr("0.0.0.0"); //本地IP加入到上面的多播组(自己的ip)
- setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&group,sizeof(group));
- printf("加组成功\n");
-
- //2.绑定 ip+port 填充结构体
- struct sockaddr_in saddr;
- saddr.sin_family = AF_INET;
- saddr.sin_port = htons(atoi(argv[2]));
- saddr.sin_addr.s_addr = inet_addr(argv[1]);
- socklen_t len = sizeof(saddr); //结构体大小
- //bind绑定ip和端口
- if (bind(sockfd, (struct sockaddr *)&saddr, len) < 0)
- {
- perror("bind err");
- return -1;
- }
- printf("bind success\n");
- char buf[128] = {0};
- while (1)
- {
- //接收信息
- if (recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&saddr, &len) < 0)
- {
- perror("recvfrom err");
- return -1;
- }
- printf("client ip:%s ,port:%d buf:%s\n", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port), buf);
- }
- close(sockfd);
- return 0;
- }
-
· unix网络编程最开始有的编程都是一台主机内进程和进程之间的编程。(本地通信)
· socket同样可以用于本地间进程通信, 创建套接字时使用本地协议AF_LOCAL或AF_UNIX
· 分为流式套接字和数据报套接字
· 和其他进程间通信相比使用方便、效率更高,常用于前后台进程通信。
unix域套接字编程,实现本间进程的通信,依赖的是s类型的文件;(套接字文件)
TCP,UDP 都是依赖IP 端口号进行通信,实现两个主机通信
本地通信不需要ip和端口,所以无法进行两个主机通信
核心代码:
- #include <sys/socket.h>
- #include <sys/un.h>
-
- struct sockaddr_un {
- sa_family_t sun_family; /* 本地协议 AF_UNIX */
- char sun_path[UNIX_PATH_MAX]; /* 本地路径 s类型的套接字文件 */
- };
-
- unix socket = socket(AF_UNIX, type, 0); //type为流式或数据包套接字
-
- struct sockaddr_un myaddr;
- myaddr.sun_family = AF_UNIX; //填充UNIX域套接字
- strcpy(saddr.sun_path,"./myunix"); // 创建套接字的路径(将套接字创建到哪? 服务器与客户端一致)