Socket进阶程序设计(一)
套接字选项
套接字创建之后,可使用套接字选项设置套接字的属性,以改变套接字的行为
1.setsockopt()
int setsockopt(SOCKET s, int level, int optname, const char *optval, int optlen)
函数功能:设置套接字选项
参数:第一个参数是套接字句柄
第二个参数指定此选项被定义在哪个级别,SOL_SOCKET,IPPROTO_TCP, IPPROTO_IP等
第三个参数是设置的套接字选项名称
第四个参数指定一个缓冲区用来存放设置的选项
第五个参数是第四个参数的大小,即指定的缓冲区大小
返回:如果函数执行成功,返回0,执行失败,返回SOCKET_ERROR
注:
套接字选项的级别:
协议是分层的,每层有多个协议,不同层对应不同的级别
1) 最高层是应用层,套接字就工作在这一层,这一层的属性对应着SOL_SOCKET级别
2) 在下层是传输层,这层有TCP和UDP协议,分别对应着IPPROTO_TCP, IPPROTO_UDP级别
3) 在下面是网络层,有IP协议,对应着IPPROTO_IP级别等
注:
各级别的属性不同,同一级别不同协议的属性也可能不同。
目前用到的选项级别及其下的选项名称:
SOL_SOCKET级别:
1) SO_BROADCADT BOOL类型,设置套接字发送或接受广播信息,如果给定套接字已经被设置为发送或接受广播数据,查询此套接字选项将返回TRUE。
2) SO_REUSERADDR BOOL类型,如果值为TRUE,套接字可以被绑定到一个已经被另一个套接字使用的地址,默认情况下,套接字不能被绑定到一个已经使用的本地地址,然而,有时候为了达到一些特殊的目的需要重用地址,这时候就要将这个选项设置为TRUE
注:
对监听套接字,两个不同的监听套接字不能绑定到相同的本地地址去监听到来的连接,如果这样做的话,结果是未定义的。
Socket广播通信
利用广播可将数据发送给本地子网上的每个主机,必须有一些线程在机器上监听到来的数据,广播的缺点是如果多个进程都发送广播数据,网络就会阻塞,网络性能便会受到影响。
为了进行广播通信,必须打开广播选项SO_BROADCAST,然后使用recvfrom,sendto等函数收发广播数据
对广播通信,有一个特定的广播地址-255.255.255.255,广播数据都应该发送到这里
1.广播程序的发送方Sender
发送方程序:
1) 创建套接字
2) 使用setsockopt函数打开SO_BROADCAST选项
3) 设置广播地址255.255.255.255,向端口号4567不断发送广播数据
广播通信发送端程序代码:
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
//设置SO_BROADCAST选项为有效
BOOL bBroadcast = TRUE;
setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&bBroadcast, sizeof(BOOL));
//设置广播地址,255.255.255.255,广播端口(电台)是4567
SOCKADDR_IN bcast;
bcast.sin_family = AF_INET;
bcast.sin_addr.s_addr = INADDR_BROADCAST;
bcast.sin_port = htons(4567);
//发送广播
printf(“开始向4567端口发送广播数据…\n\n”);
char sz[] = “hello world”;
while(TRUE)
{
sendto(s, sz, strlen(sz)+1, 0, (sockaddr *)&bcast, sizeof(bcast));
sleep(5000);
}
注:
设置套接字选项时,我们需要指定选项所在的级别,选项名,设定一个char*类型的缓冲区存放选项的值,传入这个缓冲区的地址,并在随后的参数指定选项的值的内存大小
(单位是字节)
Socket相关的API中,当我们需要向API传入一个值时,通常定义一个缓冲区存放这个值,把这个缓冲区的起始地址作为char *传入,并用随后的一个参数指明这个值占用的内存大小,这样就可以正确的取出这个值了
将广播通信的端口号看做电台的频率,广播程序不断向端口号发送数据就好像是电台播放节目一样,接受程序只要绑定到特定端口号,调用recvfrom函数即可接受到广播数据,和其他UPD程序没什么不同。
广播通信接收端Reciever:
- 创建一个套接字
- 绑定到一个本地地址,指明广播端口号
- 接受广播
注:
接受广播通信时不需要设置套接字选项,只需要把接受程序绑定到广播电台端口,调用recvfrom函数即可接受到广播数据即可,和其他UDP程序没什么不同,就好像收听电台时只需调整自己的频率到广播端口就可以收到数据一样。
即发送端设定一个电台,接收端只需把频道调到这个电台就可收到广播数据
接收端程序段:
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
//首先要绑定一个本地地址,指明广播端口号
SOCKADDR_IN sin;
sin.sin_family = AF_INET;
sin.sin_addr.S_un.S_addr = INADDR_ANY;
sin_sin_port = ntohs(4567);
int err = bind(s, (SOCKADDR *)&sin, sizeof(sin));
if(SOCKET_ERROR == err)
{
printf(“bind error\n”);
return;
}
//接受广播
printf(“开始在4567端口接受广播数据…\n\n”);
SOCKADDR_IN addrRemote;
int nLen = sizeof(addrRemote);
char sz[256];
while(TRUE)
{
int nRet = recvfrom(s, sz, 256, 0, (SOCKKADDR *)&addrRemote, &nLen);
printf(“%s”,sz);
}
注:
广播程序只能应用在本地子网中,因为没有路由器转发广播数据。