使用UDP进行广播
如果通信只能在两个单体之间完成,这样的方式是没有效率的。另一方面,广播允许同时要多个接收者传播信息。
在这一章,我们将会学习下列内容:
建立一个UDP广播套接口
使用套接口发送广播信息
使用套接口接收广播信息
在学完这一章之后,我们就会知道如何使用IPv4套接口广播程序来编写程序。
理解广播地址
要使用广播,我们必须了解IPv4的特定广播地址编写。我们可以记起IP地址可以分为左边的网络ID部分以及右边的主机ID部分。广播地址所用的约定就是主机ID位全部设置为1。
当我们的网卡正确配置以后,我们可以用下面的命令来显示我们所选用接口的广播地址:
# ifconfig eth0
eth0 Link encap:Ethernet HWaddr 00:A0:4B:06:F4:8D
inet addr:192.168.0.1 Bcast:192.168.0.255 Mask:255.255.255.0
UP BROADCAST RUNNING PROMISC MULTICAST MTU:1500 Metric:1
RX packets:1955 errors:0 dropped:0 overruns:0 frame:31
TX packets:1064 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
Interrupt:9 Baseaddress:0xe400
#
输出的第二行表明eth0接口的广播地址为192.168.0.255。这个地址的网络ID为前三个字节192.168.0,而这个地址的主机ID部分为255。这个值255为是表示主机ID全为1的十进制数。
在255.255.255.255上进行广播
特殊的广播地址255.255.255.255也可以用于广播。仅管这种格式的广播地址也许表示向全世界进行广播,但是却有更多的限制。这种广播类型绝不会被路由器路由,而一个更为特殊的广播地址,例如192.168.0.255也许会被路由,而这取决于路由器的配置。
一个通常的广播地址,如255.255.255.255,并没有被很好的进行定义。例如,一些UNIX会将其解析来表明一个广播应发生在主机的所有网络接口上,而其他的一些UNIX内核只会选择其中的一个接口,通常是第一个定义的。当一个主机有多个网卡时,这就会成为一个问题。正是由于这个原因,并不鼓励通用广播地址的使用。
如果必须向每个网络接口广播,那么我们的软件在广播之前应执行下面的步骤:
1 确定下一个或第一个接口名字
2 确定接口的广播地址
3 使用这个广播地址进行广播
4 对于系统中其余的活动网络接口重复执行步骤1到步骤3
在执行完这些步骤以后,我们就可以认为已经对我们软件中的每一个接口进行广播。
这一章的其余内容会专注于如何对一个网络接口进行广播。在我们掌握了这些概念以后,如果我们必须对第一个接口进行广播,我们就可以应用前面的步骤。
加强mkaddr.c子函数
我们在第10章所提供的mkaddr.c子程序的一个限制就是他不可以很好的处理255.255.255.255广播地址的情况。在这一部分,我们将会看到修正这个问题的原因。
下面的diff输出显示了为修正这个问题而在mkaddr.c源码中所做出的改变。应用这个改变可以允许我们使用255.255.255.255广播地址进行试验。
$ diff ../ch.11/mkaddr.c mkaddr.c
99,102c99,100
< ap->sin_addr.s_addr =
< inet_addr(host_part);
< if ( ap->sin_addr.s_addr
< == INADDR_NONE )
---
> if ( !inet_aton(host_part,
> &ap->sin_addr) )
$
前面的例子显示了inet_aton函数替换了有更多限制的inet_addr函数。inet_addr函数的问题在于当地址不可用时会返回INADDR_NONE值。当255.255.255.255转换为一个32位值时,他的返回值与INADDR_NONE相同。
因而就不能区分一个错误的IP地址输入与一个通用的广播地址。使用inet_aton函数可以避免这个问题。
由一个服务器广播
这一章将会演示一个简单的广播服务器程序与一个相对应的客户端程序。我们首先将会提供并解释服务器程序。
在这里所提供的服务器将会提供一个股票市场的索引模拟。服务器程序将会由外部的交易提供者处得到数据反馈,然后向所有感兴趣的客户广播股票市场索引交易。下面显示了stksrv.c服务器程序:
/*stksrv.c
*
* Example Stock Index Broadcast:
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
extern int mkaddr(void *addr,
int *addrlen,
char *str_addr,
char *protocol);
#define MAXQ 4
static struct
{
char *index;
int start;
int volit;
int current;
}quotes[] =
{
{"DJIA",1030330,375},
{"NASDAQ",276175,125},
{"S&P 500",128331,50},
{"TSE 300",689572,75}
};
/*
* Initialize:
*/
static void initialize(void)
{
short x;
time_t td;
/*
* seed the random number generator:
*/
time(&td);
srand((int)td);
for(x=0;x<MAXQ;++x)
quotes[x].current = quotes[x].start;
}
/*
* randomly change one index quotation:
*/
static void gen_quote(void)
{
short x; /*index*/
short v; /* volatility of index */
short h; /* half of v */
short r; /* random change */
x = rand() % MAXQ;
v = quotes[x].volit;
h = (v/2) -2;
r = rand() % v;
if(r<h)
r = -r;
quotes[x].current += r;
}
/*
* This function report the error and
* exits back to the shell:
*/
static void bail(const char *on_what)
{
fputs(strerror(errno),stderr);
fputs(": ",stderr);
fputs(on_what,stderr);
fputc('\n',stderr);
exit(1);
}
int main(int argc,char **argv)
{
short x; /* index of stock indexes */
double I0; /* initial index value */
double I; /* index value */
char bcbuf[512],*bp;/* buffer and ptr */
int z; /* status return code */
int s; /* socket */
struct sockaddr_in adr_srvr; /* AF_INET */
int len_srvr; /* length */
struct sockaddr_in adr_bc; /* AF_INET */
int len_bc; /* length */
static int so_broadcast = TRUE;
static char
*sv_addr = "127.0.0.1:*",
*bc_addr = "127.255.255.255:9097";
/*
* Form a server address:
*/
if(argc >2)
/* server address */
sv_addr = argv[2];
if(argc >1)
/* broadcast address */
bc_addr = argv[1];
/*
* Form the server address:
*/
len_srvr = sizeof adr_srvr;
z = mkaddr(
&adr_srvr, /* returned address */
&len_srvr, /* returned length */
sv_addr, /* input string addr */
"udp"); /* udp protocol */
if(z==-1)
bail("bad server address");
/*
* Form the broadcast address:
*/
len_bc = sizeof adr_bc;
z = mkaddr(
&adr_bc, /* returned address */
&len_bc, /* returned length */
bc_addr, /* input string addr */
"udp"); /* udp protocol */
if(z==-1)
bail("bad broadcast address");
/*
* Create a UDP socket to use:
*/
s = socket(AF_INET,SOCK_DGRAM,0);
if(s==-1)
bail("socket()");
/*
* Allow broadcasts:
*/
z = setsockopt(s,
SOL_SOCKET,
SO_BROADCAST,
&so_broadcast,
sizeof so_broadcast);
if(z==-1)
bail("setsockopt(SO_BROADCAST)");
/*
* bind an address to our socket,so that
* client programs can listen to this
* server
*/
z = bind(s,(struct sockaddr *)&adr_srvr,len_srvr);
if(z==-1)
bail("bind()");
/*
* Now start serving quotes:
*/
initialize();
for(;;)
{
/*
* update on quote in the list:
*/
gen_quote();
/*
* Form a packet to send out:
*/
bp = bcbuf;
for(x=0;x<MAXQ;++x)
{
I0 = quotes[x].start / 100.0;
I = quotes[x].current /100.0;
sprintf(bp,
"%-7.7s %8.2f %+.2f\n",
quotes[x].index,
I
I-I0);
bp += strlen(bp);
}
/*
* broadcast the updated info:
*/
z = sendto(s,bcbuf,strlen(bcbuf),0,(struct sockaddr *)&adr_bc,len_bc);
if(z==-1)
bail("sendto()");
sleep(4);
}
return 0;
}
接收广播
我们所提供的客户端程序必须监听我们的股票市场索引程序所发布的广播。下面是客户端程序的源码:
/*gquotes.c
*
* Get datagram stock market
* quotes from udp broadcast:
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
extern int mkaddr(
void *addr,
char *addrlen,
char *str_addr,
char *protocol);
/*
* This function report the error and
* exits back to the shell:
*/
static void bail(const char *on_what)
{
fputs(strerror(errno),stderr);
fputs(": ",stderr);
fputs(on_what,stderr);
fputc('\n',stderr);
exit(1);
}
int main(int argc,char **argv)
{
int z;
int x;
struct sockaddr_in adr; /* AF_INET */
int len_inet; /* length */
int s; /* socket */
char dgram[512]; /* recv buffer */
static int so_reuseaddr = TRUE;
static char
*bc_addr = "127.255.255.255:9097";
/*
* use a server address from the command
* line,if one has been provided.
* otherwise,this program will default
* to using the arbitrary address
* 127.0.0.23:
*/
if(argc>1)
/* broadcast address: */
bc_addr = argv[1];
/*
* Create a UDP socket to use:
*/
s = socket(AF_INET,SOCK_DGRAM,0);
if(s==-1)
bail("socket()");
/*
* Form the broadcast address:
*/
len_inet = sizeof adr;
z = mkaddr(&adr,
&len_inet,
bc_addr,
"udp");
if(z==-1)
bail("bad broadcast address");
/*
* Allow multiple listeners on the
* broadcast address:
*/
z = setsockopt(s,
SOL_SOCKET,
SO_REUSEADDR,
&so_reuseaddr,
sizeof so_reuseaddr);
if(z==-1)
bail("setsockopt(SO_REUSEADDR)");
/*
* bind out socket to the broadcast address:
*/
z = bind(s,
(struct sockaddr *)&adr,
len_inet);
if(z==-1)
bail("bind(2)");
for(;;)
{
/*
* wait for a broadcast message:
*/
z = recvfrom(s, /*socket */
dgram, /* receiving buffer */
sizeof dgram, /* max rcv buf size */
0, /* flags:no options */
(struct sockaddr *)&adr, /* addr */
&x); /* addr len */
if(z<0)
bail("recvfrom(2)");
fwrite(dgram,z,1,stdout);
putchar('\n');
fflush(stdout);
}
return 0;
}
分享到:
相关推荐
Linux Socket学习(八).txt和Linux Socket学习(十).txt可能涉及到连接建立和接受过程。对于服务器端,accept()函数用于接收客户端的连接请求;对于客户端,connect()函数用于发起连接。这两部分的细节是理解TCP/...
《实战Linux Socket编程》是...总之,《实战Linux Socket编程》的配套源代码是一个宝贵的资源,它使学习者能够动手实践,从而更好地掌握网络编程的核心概念和技术,对于提升Linux系统下的网络编程能力具有重要意义。
在IT行业中,Linux Socket是进行网络通信的重要工具,尤其对于系统和网络程序员来说,理解和掌握Linux Socket编程至关重要。本示例代码提供了客户端(client)和服务器端(server)的实现,帮助初学者深入理解如何在...
在IT领域,Linux Socket编程是网络通信的核心技术之一,它为开发者提供了在Linux操作系统上实现进程间通信(IPC)和网络通信的接口。本实战指南将深入探讨这一主题,帮助你掌握如何在Linux环境中构建高效的网络应用...
在Linux操作系统中,Socket是一种进程间通信机制,它允许不同进程或者不同计算机之间的通信。本教程将深入探讨Linux下的socket编程,包括服务器和客户端的实现。我们主要关注以下几个知识点: 1. **Socket基本概念*...
本压缩包“linuxsocket.zip”包含了基于TCP/IP协议的socket通信测试代码,是学习Linux应用编程的一个实用资源。这里我们将深入探讨Linux TCP/IP socket编程的相关知识点。 1. **TCP/IP协议栈**:TCP/IP协议栈是...
本篇文章将根据给定文件“linux socket学习.pdf”的内容进行展开,重点讨论 socket 的定义、如何创建 socket 以及 socket 与其他常见 I/O 操作的区别。 #### 二、理解 Socket ##### 2.1 定义 Socket Socket 可以...
通过本书的学习,读者可以掌握如何在Linux环境中使用Socket进行网络通信,构建高性能、稳定的网络应用。下面将根据提供的压缩包文件名“实战 Linux Socket编程代码”来解析其中可能包含的知识点。 1. **Socket基础...
Linux Socket是Linux操作系统中用于进程间通信(IPC)的一种接口,它允许程序通过网络协议进行数据传输。在本文中,我们将深入探讨Linux ...通过IBM技术论坛的文章,你可以更深入地了解和学习Linux Socket的各种细节。
Linux Socket编程是网络编程的重要组成部分,它为开发者提供...通过这个实战教程,开发者将学习如何在Linux环境中创建和管理Socket,实现网络通信功能,这对于开发服务器应用、网络工具或分布式系统是至关重要的技能。
在Linux操作系统中,Socket接口是应用程序与网络协议交互的主要接口,它允许程序通过网络发送和接收数据。在本文中,我们将深入探讨“Linux Socket网络驱动深度分析”这一主题,特别是当应用尝试创建一个用于捕获...
### Linux Socket Programming (Linux 套接字编程) #### 知识点概览: 1. **Socket编程基础** ...通过以上知识点的学习,读者可以深入了解Linux环境下的Socket编程,并能够掌握如何设计和实现网络通信程序。
Linux Socket实战编程是深入理解网络通信机制的...总的来说,这份资源对于想要深入理解和精通Linux Socket编程的IT从业者来说是一份宝贵的资料,通过学习和实践,可以显著提升网络编程能力,为职业发展打下坚实基础。
Gay撰写,为读者提供了丰富的实例和深入的理论知识,是学习Linux Socket编程的绝佳资源。 **二、基本Socket概念** ### 1. Socket简介 在Linux环境下,Socket是一种进程间通信(IPC)的方式,它提供了一种在两个...
10. **学习资源**:学习Socket编程,可以参考《UNIX Network Programming》等经典书籍,同时网上有许多关于Linux Socket编程的教程和示例代码可供学习。 总之,"Linux下的socket聊天室程序"是一个很好的实践项目,...
在IT行业中,网络通信是至关重要的部分,而Linux Socket编程是实现这一目标的关键技术。Socket是一种接口,允许应用程序通过网络发送和接收数据。本篇将深入探讨标题为"Linux Socket两则示例"的资源,其中包括`echo_...
《Linux Socket编程示例》...以上仅为《Linux Socket编程示例》部分章节的知识点总结,实际书中还包含了更多深入的技术细节和实战案例,对于希望掌握Linux环境下网络编程技术的学习者而言,是一本不可多得的参考书籍。
Linux Socket编程是网络编程的重要组成部分,它允许...总之,"实战Linux Socket编程源码"提供了一个实践Socket编程和多客户端处理的平台,通过对源代码的学习和分析,可以加深对Socket编程的理解,提升网络编程技能。
本资源“实战Linux Socket编程”旨在帮助你深入理解并掌握这一关键技能,尤其对于那些希望在嵌入式领域有所建树的开发者来说,它是不可或缺的学习资料。 在Linux系统中,Socket编程主要涉及以下几大知识点: 1. **...