Multicast 不用多说,组播,既然要做multicast开发,肯定得知道multicast是什么;
windows和linux下开发的multicast的代码如下,具体的讲解,看代码注释:
<script type="text/javascript"><!-- google_ad_client = "pub-8565472114859759"; /* 180x150, 创建于 08-7-7 */ google_ad_slot = "4647145443"; google_ad_width = 180; google_ad_height = 150; //--> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
C/C++ code
/*Multicast Client.c support Linux & Windows
*Zhao.kaiyong(a)gmail.com
*http://blog.csdn.net/openhero
*可以转载,可以复制,修改,如果有修改,请给我来一封email:)谢谢
*/
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->
#include
<
stdio.h
>
#include
<
stdlib.h
>
#include
<
string
.h
>
#ifdef _WIN32
#include
<
winsock2.h
>
#include
<
io.h
>
#include
<
Ws2tcpip.h
>
#pragma
comment(lib, "ws2_32.lib")
#else
#include
<
sys
/
types.h
>
#include
<
sys
/
socket.h
>
#include
<
netinet
/
in
.h
>
#include
<
arpa
/
inet.h
>
#include
<
unistd.h
>
#include
<
errno.h
>
#define
closesocket close
#endif
#define
BUF_SIZE 0x1000
char
*
host_name
=
"
224.1.1.3
"
;
int
port
=
12345
;
int
main(
int
argc,
char
*
argv[])
{
int
loop
=
1
;
/*
多播循环
*/
int
iter
=
0
;
int
from_len;
char
buffer[BUF_SIZE];
int
socket_descriptor;
struct
ip_mreq command;
struct
sockaddr_in loc;
struct
sockaddr_in rem;
int
rec_len
=
0
;
int
ptr_point
=
0
;
size_t bytes_written
=
0
;
int
loop_times
=
0
;
int
rcv_port_0
=
0
;
int
rcv_port_1
=
0
;
int
first
=
0
;
#ifdef _WIN32
WSADATA wsaData;
if
( WSAStartup(MAKEWORD(
2
,
2
),
&
wsaData)
!=
0
)
{
printf(
"
Error in WSAStartup/n
"
);
exit(
1
);
}
#endif
if
(argv[
1
])
{
host_name
=
argv[
1
];
printf(
"
%s /n
"
, host_name);
}
if
(argv[
2
])
{
port
=
atoi(argv[
2
]);
printf(
"
%d /n
"
, port);
}
memset(
&
loc,
0
,
sizeof
(loc));
loc.sin_family
=
AF_INET;
//这个地方很重要,不然linux下就只能是broadcast;所以必须指定组播的地址;
loc.sin_port
=
htons(port);
loc.sin_addr.s_addr
=
inet_addr(host_name);
if
((socket_descriptor
=
socket(AF_INET, SOCK_DGRAM,
0
))
==
-
1
)
{
perror(
"
socket
"
);
exit(EXIT_FAILURE);
}
/*
can use the same port in the pc
*/
loop
=
1
;
if
(setsockopt(socket_descriptor, SOL_SOCKET, SO_REUSEADDR,
&
loop,
sizeof
(loop))
<
0
)
{
perror(
"
setsockopt:SO_REUSEADDR./n
"
);
exit(EXIT_FAILURE);
}
else
{
printf(
"
setsockopt:SO_REUSEADDR./n
"
);
}
loop
=
0x1000000
;// 设置网络的接收buffer的大小
if
( setsockopt( socket_descriptor, SOL_SOCKET, SO_RCVBUF, (
void
*
)
&
loop,
sizeof
( loop ) )
<
0
)
{
perror(
"
setsockopt:SO_RCVBUF./n
"
);
exit(EXIT_FAILURE);
}
//由于在前面指定了组播的地址,但是在winodws和linux下不一样,就得这么处理,这个细节来之分析VLC源代码
#if defined( WIN32 ) || defined( UNDER_CE )
/*
* Under Win32 and for multicasting, we bind to INADDR_ANY.
* This is of course a severe bug, since the socket would logically
* receive unicast traffic, and multicast traffic of groups subscribed
* to via other sockets. How this actually works in Winsock, I don't
* know.
*/
if
( IN_MULTICAST( ntohl( loc.sin_addr.s_addr ) ) )
{
struct
sockaddr_in stupid
=
loc;
stupid.sin_addr.s_addr
=
INADDR_ANY;
if
( bind( socket_descriptor, (
struct
sockaddr
*
)
&
stupid,
sizeof
( stupid ) )
<
0
)
{
perror(
"
bind socket./n
"
);
close( socket_descriptor );
return
0
;
}
}
else
#endif
if
(bind(socket_descriptor, (
struct
sockaddr
*
)
&
loc,
sizeof
(loc))
<
0
)
{
perror(
"
bind socket./n
"
);
exit(EXIT_FAILURE);
}
{ //加入组播组,如果有多块网卡,可以用另一个变量来特别设置;
printf(
"
%s,%d/n
"
, host_name, port);
command.imr_multiaddr.s_addr
=
inet_addr(host_name);
command.imr_interface.s_addr
=
htonl(INADDR_ANY);
if
(command.imr_multiaddr.s_addr
==
-
1
)
{
perror(
"
224.1.1.3 not a legal multicast address./n
"
);
exit(EXIT_FAILURE);
}
if
(setsockopt(socket_descriptor, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&
command,
sizeof
(command))
<
0
)
{
perror(
"
setsockopt:IP_ADD_MEMBERSHIP. error/n
"
);
}
}
printf(
"
start reciving.../n
"
);
from_len
=
sizeof
(rem);
while
(
1
)
{
memset(
&
rem,
0
, from_len);
memset(buffer,
0
, BUF_SIZE);
if
( (rec_len
=
recvfrom(socket_descriptor, buffer,
sizeof
(
char
)
*
BUF_SIZE,
0
, (
struct
sockaddr
*
)
&
rem,
&
from_len))
==
-
1
) {
perror(
"
recvfrom./n
"
);
}
printf(
"
From host:%s port:%d, len: %d/n
"
, inet_ntoa(rem.sin_addr), ntohs(rem.sin_port), rec_len);
}
if
(setsockopt(socket_descriptor, IPPROTO_IP, IP_DROP_MEMBERSHIP,
&
command,
sizeof
(command))
<
0
) {
perror(
"
setsockopt:IP_DROP_MEMBERSHIP./n
"
);
}
closesocket(socket_descriptor);
exit(EXIT_SUCCESS);
}
注:
1.在windows中不需要特殊的设置网络;
2.在Linux下得特别注意网络的设置,有下面几个环节:
1)查看内核模块,是否已经加载了multicast支持;这个可以通过 在src目录下面 make menuconfig 查看ip 设置栏目看到;
2)查看网络是否已经加载了multicast支持;命令:ip a 可以看到现在网络支持的各个功能;
3)添加multicast 网络路由:net add -net 224.0.0.0 netmask 240.0.0.0 dev eth0
这样才能启动网络的multicast路由支持,不然只能当作broadcast处理。