获取/设置套接字属性
-
1、getsockopt()获取套接字属性
-
2、setsockopt()设置套接字属性
-
参数
- sockfd:套接字文件描述符
- level:设置属性层
- SOL_SOCKET:通用套接字层
- IPPROTO_IP:IP层
- IPPRO_TCP:TCP层
- optname:指定操作,一般用宏表示
- optval:设置属性对应的值
- optlen:设置属性对应长度
-
返回值
- 成功返回 0,失败返回-1
level网络属性设置
* SOL_SOCKET
| optname | optval类型 |
| ------------------------------------------ | -------------- |
| **SO_BROADCAST** 允许发送广播数据 | int |
| SO_DEBUG 允许调试 | int |
| SO_DONTROUTE 不查找路由 | int |
| SO_ERROR 获得套接字错误 | int |
| SO_KEEPALIVE 保持连接 | int |
| SO_LINGER 延迟关闭连接 | struct linger |
| SO_OOBINLINE 带外数据放入正常数据流 | int |
| SO_RCVBUF 接收缓冲区大小 | int |
| SO_SNDBUF 发送缓冲区大小 | int |
| SO_RCVLOWAT 接收缓冲区下限 | int |
| SO_SNDLOWAT 发送缓冲区下限 | int |
| SO_RCVTIMEO 接收超时 | struct timeval |
| SO_SNDTIMEO 发送超时 | struct timeval |
| **SO_REUSEADDR** 允许重用本地地址和端口 | int |
| SO_TYPE 获得套接字类型 | int |
| SO_BSDCOMPAT 与BSD系统兼容 | int |
* IPPROTO_IP
| optname | optval类型 |
| -------------------------------------------------- | -------------- |
| IP_ADD_MEMBERSHIP 将指定IP加入到组播组中 | struct ip_mreq |
| IP_MULTICAST_IF 允许开启组播报文的接口 | struct ip_mreq |
* IPPRO_TCP
| optname | optval类型 |
| ------------------------------- | ---------- |
| TCP_MAXSEG TCP最大数据段的大小 | int |
| TCP_NODELAY 不使用Nagle算法 | int |
网络地址
-
A类地址
- 第一字节为网络地址,其他3个字节为主机地址。第一字节的最高位固定为0
1.0.0.1—126.255.255.255
- 第一字节为网络地址,其他3个字节为主机地址。第一字节的最高位固定为0
-
B类地址
- 第一字节和第二字节是网络地址,其他2个字节是主机地址。第一字节的前三位固定为10
128.0.0.1—191.255.255.255
- 第一字节和第二字节是网络地址,其他2个字节是主机地址。第一字节的前三位固定为10
-
C类地址
- 前三个字节是网络地址,最后一个字节是主机地址。第一字节的前三位固定为110
192.0.0.1—223.255.255.255
- 前三个字节是网络地址,最后一个字节是主机地址。第一字节的前三位固定为110
-
D类地址(组播地址)
- 不分网络地址和主机地址,第一个字节的前四位固定为1110
224.0.0.1—239.255.255.255
- 不分网络地址和主机地址,第一个字节的前四位固定为1110
广播
- 同时发给局域网中的所有主机
- IP:192.168.7.215 子网掩码:255.255.255.0 则网络号为:192.168.7(ip和掩码相与) 广播地址为:192.168.7.255
- 只有用户数据报(使用UDP协议)套接字才能广播
- 255.255.255.255在所有网段中都代表广播地址
1、发送方——客户端
-
创建用户数据报套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0)
-
缺省创建的套接字不允许广播数据包,需要设置属性
setsockopt可以设置套接字属性
int opt = 1;
setsockopt(sockfd, SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt)); -
接收方地址指定为广播地址,指定端口信息
struct sockaddr_in saddr;
saddr.sin_port = htons(8989);
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr("192.168.7.255");
-
发送数据包
char sendbuf[32] = {0};
while(1)
{
read(0, sendbuf, sizeof(sendbuf));
sendto(sockfd, sendbuf, sizeof(sendbuf), (struct sockaddr*)&saddr, sizeof(saddr));
memset(sendbuf, 0, sizeof(sendbuf));
} -
#include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <unistd.h> int main(int argc, char *argv[]) { //创建用户数据报套接字 int sockfd = socket(AF_INET,SOCK_DGRAM,0); //缺省创建的套接字不允许广播数据包,需要设置属性 //setsockopt可以设置套接字属性 int opt = 1; setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt)); //接收方地址指定为广播地址 指定端口信息 struct sockaddr_in saddr; saddr.sin_family = AF_INET; saddr.sin_port = htons(8848); saddr.sin_addr.s_addr = inet_addr("192.168.7.255"); //循环发送数据包 char sendBuf[32] = {0}; while(1) { read(0,sendBuf,sizeof(sendBuf)); sendto(sockfd,sendBuf,sizeof(sendBuf),0,(struct sockaddr *)&saddr,sizeof(saddr)); } return 0; }
2、接收方——服务器
-
创建用户数据报套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0)
-
绑定ip地址和端口
struct sockaddr_in saddr;
saddr.sin_port = htons(8989);
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr("192.168.7.255");
bind(sockfd, (struct sockaddr*)&saddr,sizeof(saddr)); -
等待接收数据
char recvbuf[32] = {0};
while(1)
{
recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0,NULL,NULL);
memset(recvbuf, 0 , sizeof(recvbuf));
} -
发送数据包
char sendbuf[32] = {0};
while(1)
{
read(0, sendbuf, sizeof(sendbuf));
sendto(sockfd, sendbuf, sizeof(sendbuf), (struct sockaddr*)&saddr, sizeof(saddr)); -
#include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <unistd.h> int main(int argc, char *argv[]) { //创建用户数据报套接字 int sockfd = socket(AF_INET,SOCK_DGRAM,0); //绑定IP地址(广播IP或0.0.0.0)和端口 struct sockaddr_in saddr; saddr.sin_family = AF_INET; saddr.sin_port = htons(8848); saddr.sin_addr.s_addr = inet_addr("192.168.7.255"); //绑定的端口必须和发送方指定的端口相同 bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr)); //等待接收数据 char recvBuf[32] = {0}; while(1) { recvfrom(sockfd,recvBuf,sizeof(recvBuf),0,NULL,NULL); printf("recvBuf:%s\n",recvBuf); memset(recvBuf,0,sizeof(recvBuf)); } return 0; }
组播
广播方式发给所有主机,过多的广播会占用大量的网络带宽,造成广播风暴,影响正常通信。
组播又称为多播,是一种折中的方式,只有加入某个多播组的主机才能接收到数据。
多播方式既可以发给多个主机,又能避免像广播那样带来过多的负载(每台主机要到传输层才能判断广播包是否要处理)。
发送方
-
创建用户数据报套接字
int sockfd = socket(AF_INET,SOCK_DGRAM,0); -
接收方地址指定为组播地址
- 指定端口信息
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(8848);
saddr.sin_addr.s_addr = inet_addr("224.10.10.10"); -
发送数据包
char sendBuf[32] = {0};
while(1)
{
read(0,sendBuf,sizeof(sendBuf));
sendto(sockfd,sendBuf,sizeof(sendBuf),0,(struct sockaddr *)&saddr,sizeof(saddr));
} -
#include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <unistd.h> int main(int argc, char *argv[]) { //创建用户数据报套接字 int sockfd = socket(AF_INET,SOCK_DGRAM,0); //接收方地址指定为组播地址 指定端口信息 224.10.10.10 struct sockaddr_in saddr; saddr.sin_family = AF_INET; saddr.sin_port = htons(8848); saddr.sin_addr.s_addr = inet_addr("224.10.10.10"); //发送数据包 char sendBuf[32] = {0}; while(1) { read(0,sendBuf,sizeof(sendBuf)); sendto(sockfd,sendBuf,sizeof(sendBuf),0,(struct sockaddr *)&saddr,sizeof(saddr)); } return 0; }
接收方
-
创建用户数据报套接字
int sockfd = socket(AF_INET, SOCK_DGRAM,0); -
加入多播组
/*
struct ip_mreq {
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_interface; /* local IP address of interface */
};
*/
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.10");
mreq.imr_interface.s_addr = inet_addr("0.0.0.0");
setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)); -
绑定IP地址(加入组的IP或0.0.0.0)和端口(绑定的端口必须和发送方指定的端口相同)
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(8848);
saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr)); -
接收数据
char recvBuf[32] = {0};
while(1)
{
recvfrom(sockfd,recvBuf,sizeof(recvBuf),0,NULL,NULL);
printf("recvBuf:%s\n",recvBuf);
memset(recvBuf,0,sizeof(recvBuf));
}
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
//创建用户数据报套接字
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
//加入多播组
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("224.10.10.10");
mreq.imr_interface.s_addr = inet_addr("0.0.0.0");
setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
//绑定IP地址(加入组的组IP或0.0.0.0)和端口 绑定的端口必须和发送方指定的端口相同
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(8848);
saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
//等待接收数据
char recvBuf[32] = {0};
while(1)
{
recvfrom(sockfd,recvBuf,sizeof(recvBuf),0,NULL,NULL);
printf("recvBuf:%s\n",recvBuf);
memset(recvBuf,0,sizeof(recvBuf));
}
return 0;
}