一、网络属性
1> 对于套接字而言,在不同的层中,可以设置不同的属性,如端口号快速重用、超时时间、设置广播、加入多播组等等
2> 关于网络属性,有两个函数,分别是 setsockopt、getsockopt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <sys/types.h> #include <sys/socket.h> int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); 功能:获取网络属性 参数1:套接字文件描述符 参数2:套接字要设置的层次 应用层:SOL_SOCKET tcp传输层:IPPROTO_TCP udp传输层: IPPROTO_UDP 网络层:IPPROTO_IP 参数3:指定层内的属性,见下表 参数4:存放该属性的容器起始地址 参数5:参数4的大小 返回值:成功返回0,失败返回-1并置位错误码 int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); 功能:设置网络属性 参数1:套接字文件描述符 参数2:套接字要设置的层次 应用层:SOL_SOCKET tcp传输层:IPPROTO_TCP udp传输层: IPPROTO_UDP 网络层:IPPROTO_IP 参数3:指定层内的属性,见下表 参数4:设置该属性的容器起始地址 参数5:参数4的大小 返回值:成功返回0,失败返回-1并置位错误码
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #include<myhead.h> int main(int argc, const char *argv[]) { int sfd = socket(AF_INET, SOCK_STREAM, 0); if(sfd == -1) { perror("socket error"); return -1; } int resue = -1; int resue_size = sizeof(resue); if(getsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &resue, &resue_size)==-1) { perror("getsockopt error"); return -1; } printf("resue = %d\n", resue); resue = 1; if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &resue, sizeof(resue)) == -1) { perror("setsockopt error"); return -1; } printf("端口号快速重用设置成功\n"); resue = -1; if(getsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &resue, &resue_size)==-1) { perror("getsockopt error"); return -1; } printf("resue = %d\n", resue); return 0; }
|
二、多点通信
2.1 单播
1> 单播发生在主机之间一对一的通信模式,交换机或者路由器只对数据进行转发,不做复制
2> 每次只有两个实体之间进行相互通信,发送端和接收端都是唯一确定的
2.2 广播
1> 主机之间的一对多的通信模式,网络对其中的每一台主句发出的信息都进行复制并转发
2> 所有主机都可以收到广播消息(无论你是否愿意接收),所以,广播是基于UDP通信模式
3> 广播地址:网络号 + 255
例如:主机地址为192.168.125.171 —> 192.168.125.255
4> 广播消息是不能穿过路由器的,也就是说广播消息禁止在外网上进行传播,所以广播只能完成局域网内的多点通信
2.3 广播的发送端模型 ----> 类似于UDP的客户端
1> socket 创建套接字
2> setsockopt 设置网络属性,允许广播
3> bind 非必须绑定
4> 填充接收端地址信息结构体
ip:填广播地址(192.168.125.255)
port:与接收端保持一致
5> sendto 发送消息
6> close 关闭套接字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #include<myhead.h> int main(int argc, const char *argv[]) { int sfd = socket(AF_INET, SOCK_DGRAM, 0); if(sfd == -1) { perror("socket error"); return -1; } int broadcast = 1; if(setsockopt(sfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast))==-1) { perror("setsockopt error"); return -1; } struct sockaddr_in cin; cin.sin_family = AF_INET; cin.sin_port = htons(6789); cin.sin_addr.s_addr = inet_addr("192.168.125.255"); char sbuf[128] = ""; while(1) { printf("请输入>>>"); fgets(sbuf, sizeof(sbuf), stdin); sbuf[strlen(sbuf)-1] = 0; sendto(sfd, sbuf, sizeof(sbuf), 0, (struct sockaddr*)&cin, sizeof(cin)); printf("发送成功\n"); } close(sfd); return 0; }
|
2.4 广播的接收端模型 ----> 类似于UDP的服务器端
1> socket 创建套接字
2> 填充地址信息结构体
ip:广播地址
port:与发送端保持一致
3> bind 绑定端口号与ip地址
4> recvfrom 接收消息
5> close 关闭套接字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #include<myhead.h> int main(int argc, const char *argv[]) { int rfd = socket(AF_INET, SOCK_DGRAM, 0); if(rfd == -1) { perror("socket error"); return -1; } struct sockaddr_in rin; rin.sin_family = AF_INET; rin.sin_port = htons(6789); rin.sin_addr.s_addr = inet_addr("192.168.125.255"); if(bind(rfd, (struct sockaddr*)&rin, sizeof(rin)) == -1) { perror("bind error"); return -1; } char rbuf[128] = ""; while(1) { bzero(rbuf , sizeof(rbuf)); recvfrom(rfd, rbuf, sizeof(rbuf), 0, 0, 0); printf("收到消息为:%s\n", rbuf); } close(rfd); return 0; }
|
2.5 组播
1> 组播也是实现主机之间一对多的通信模型,跟广播不同的是,组播发送的消息,只有加入多播组的成员才能收到,没有加入的就无法收到,不会占用柜台对的网络带宽
2> 组播也是使用UDP实现
3> 组播地址:就是D类网络,224.0.0.0 – 239.255.255.255
2.6 组播的发送端模型 —>类似于UDP的客户端
1> socket 创建套接字
2> bind 非必须绑定
3> 填充接收端地址信息结构体
ip:组播地址,与接收端保持一致
port:与接收端保持一致
4> sendto 发送组播消息
5> close 关闭套接字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| #include<myhead.h> int main(int argc, const char *argv[]) { int sfd = socket(AF_INET, SOCK_DGRAM, 0); if(sfd == -1) { perror("socket error"); return -1; } struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(9999); sin.sin_addr.s_addr = inet_addr("224.1.2.3"); char sbuf[128] = ""; while(1) { printf("请输入>>>"); fgets(sbuf, sizeof(sbuf), stdin); sbuf[strlen(sbuf)-1] = 0; sendto(sfd, sbuf, sizeof(sbuf), 0, (struct sockaddr*)&sin, sizeof(sin)); printf("发送成功\n"); } close(sfd); return 0; }
|
2.7 组播的接收端模型 —> 类似于UDP的服务器
1> socket 创建套接字
2> setsockopt 设置网络属性
设置层级:IPPROTO_IP
设置属性:IP_ADD_MEMBERSHIP
属性类型:
struct ip_mreqn {
struct in_addr imr_multiaddr; /* IP multicast group address / //组播ip地址
struct in_addr imr_address; / IP address of local interface / //本地IP地址
int imr_ifindex; / interface index */ 网络索引 0表示使用默认网络索引
ip ad:查看自己的网卡索引号 ens33 —> 2
};
3> 填充地址信息结构体
ip:组播IP,与发送端保持一致
port :与发送端保持一致
4> bind 必须绑定
5> recvfrom 接收消息
6> close 关闭套接字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include<myhead.h> int main(int argc, const char *argv[]) { int rfd = socket(AF_INET, SOCK_DGRAM, 0); if(rfd == -1) { perror("socket error"); return -1; } struct ip_mreqn im; im.imr_multiaddr.s_addr = inet_addr("224.1.2.3"); im.imr_address.s_addr = inet_addr("192.168.122.118"); im.imr_ifindex = 2; if(setsockopt(rfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &im, sizeof(im)) == -1) { perror("setsockopt error"); return -1; } printf("加入多播组成功\n"); struct sockaddr_in rin; rin.sin_family = AF_INET; rin.sin_port = htons(9999); rin.sin_addr.s_addr = inet_addr("224.1.2.3"); if(bind(rfd, (struct sockaddr*)&rin, sizeof(rin)) == -1) { perror("bind error"); return -1; } char rbuf[128] = ""; while(1) { bzero(rbuf, sizeof(rbuf)); recvfrom(rfd, rbuf, sizeof(rbuf), 0, 0, 0); printf("收到消息为:%s\n", rbuf); } close(rfd); return 0; }
|
本章完