TCP/IP網路程式設計 學習筆記_15 --多播與廣播
轉自:http://blog.csdn.net/u010223072/article/details/48269213
前言:想想這麼一種情況,網路電臺可能需要同時向成千上萬的使用者傳輸相同的資料,如果用我們以前講過的傳輸形式,每個使用者都傳輸一次,這樣肯定是不合理的。因此,就引入了多播技術來解決這個問題,它可以同時向大量使用者傳送相同資料。其基本原理是這樣的:有個多播組,只要加入這個組裡的所有客服端,服務端傳送的資料它們都能收到,具體傳輸到多播組裡的每個客戶是由路由完成的(如果路由器不支援多播或網路堵塞,實現多播也會使用隧道技術)。
多播
-
多播的資料傳輸特點如下:
1,多播伺服器端針對特定多播組,只需傳送1次資料,該組內的所有所有客服端都能接收資料。
2,多播組數可在IP地址範圍內任意增加。 -
設定生存時間和加入多播組的方法
1,設定生存時間:只指服務端傳送的資料包最遠能傳遞的距離,用整數表示,並且每經過1個路由器就減1,當為0時,該資料包無法再被傳遞,只能銷燬。因此,這個值設定過大將影響網路流量。當然,設定過小也會無法傳遞到目標(通過套接字可選項設定,示例程式碼中有使用方法)。2,加入多播組:也是通過套接字可選項設定,示例程式碼中有使用方法,這裡只介紹多播組的結構體ip_mreq。
struct ip_mreq
{
struct in_addr imr_multiaddr; //多播組的IP地址
struct in_addr imr_interface; //加入的客服端主機IP地址
} -
實現多播
1,傳送者(Sender)
//
// main.cpp
// hello_server
//
// Created by app05 on 15-9-7.
// Copyright (c) 2015年 app05. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define TTL 64 //資料包生存時間,即最多可以傳遞經過第64個路由時銷燬
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, const char * argv[]) {
int send_sock;
struct sockaddr_in mul_adr;
int time_live = TTL;
FILE *fp;
char buf[BUF_SIZE];
if (argc != 3) {
printf("Usage : %s <GroupIp> <Port> \n", argv[0]);
exit(1);
}
//基於UDP的多播
send_sock = socket(PF_INET, SOCK_DGRAM, 0);
memset(&mul_adr, 0, sizeof(mul_adr));
mul_adr.sin_family = AF_INET;
mul_adr.sin_addr.s_addr = inet_addr(argv[1]);
mul_adr.sin_port = htons(atoi(argv[2]));
//設定生存時間(除了這裡其它基本和UDP編寫一樣)
setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&time_live, sizeof(time_live));
if((fp = fopen("/Users/app05/Desktop/test.txt", "r")) == NULL)
error_handling("fopen() error");
while (!feof(fp)) //如果檔案結束,則返回非0值,否則返回0
{
fgets(buf, BUF_SIZE, fp);
sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr *)&mul_adr, sizeof(mul_adr));
sleep(1); //只是為了加個傳輸資料時間間隔,沒有特殊意義
}
fclose(fp);
close(send_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(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
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
2,接受者(Receiver)
//
// main.cpp
// hello_client
//
// Created by app05 on 15-9-7.
// Copyright (c) 2015年 app05. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, const char * argv[]) {
int recv_sock;
int str_len;
char buf[BUF_SIZE];
struct sockaddr_in adr;
struct ip_mreq join_adr; //多播組結構體
if(argc != 3)
{
printf("Usage : %s <GroupIp> <Port> \n", argv[0]);
exit(1);
}
recv_sock = socket(PF_INET, SOCK_DGRAM, 0);
memset(&adr, 0, sizeof(adr));
adr.sin_family = AF_INET;
adr.sin_addr.s_addr = htonl(INADDR_ANY);
adr.sin_port = htons(atoi(argv[2]));
if(bind(recv_sock, (struct sockaddr *)&adr, sizeof(adr)) == -1)
error_handling("bind() error");
//加入多播組
join_adr.imr_multiaddr.s_addr = inet_addr(argv[1]);
join_adr.imr_interface.s_addr = htonl(INADDR_ANY);
setsockopt(recv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&join_adr, sizeof(join_adr));
while (1) {
str_len = recvfrom(recv_sock, buf, BUF_SIZE - 1, 0, NULL, 0);//只需要多播組IP地址,不關心自己主機地址
if(str_len < 0)
break;
buf[str_len] = 0;
fputs(buf, stdout);
}
close(recv_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(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
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
廣播
廣播在功能上和多播是一樣的,都是同時可以向大量客戶傳遞資料。但他們在網路範圍上有區別,多播可以跨越不同的網路,只要加入了多播組就能接收資料。但廣播只能向同一網路中的主機傳輸資料。
廣播分為:直接廣播與本地廣播,直接廣播sender的IP地址只需指定網路地址,主機地址全部填255。這樣處在這個網路地址裡的所有主機就可以接收資料了。而本地廣播sender的IP地址寫255.255.255.255,這樣本地網路所有主機就可以接收資料了。
//將SO_BROADCAST可選項設定為1就表示開啟了套接字廣播功能,預設是關閉的。
int bcast = 1;
setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (void *) &bcast, sizeof(bcast));
下面就多播的程式碼示例稍作修改,本地廣播的示例如下:
//
// main.cpp
// hello_server
//
// Created by app05 on 15-9-7.
// Copyright (c) 2015年 app05. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define TTL 64 //資料包生存時間,即最多可以傳遞經過第64個路由時銷燬
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, const char * argv[]) {
int send_sock;
struct sockaddr_in mul_adr;
int time_live = TTL;
FILE *fp;
char buf[BUF_SIZE];
if (argc != 3) {
printf("Usage : %s <GroupIp> <Port> \n", argv[0]);
exit(1);
}
//基於UDP的多播
send_sock = socket(PF_INET, SOCK_DGRAM, 0);
memset(&mul_adr, 0, sizeof(mul_adr));
mul_adr.sin_family = AF_INET;
mul_adr.sin_addr.s_addr = inet_addr(argv[1]);
mul_adr.sin_port = htons(atoi(argv[2]));
//設定生存時間(除了這裡其它基本和UDP編寫一樣)
//setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&time_live, sizeof(time_live));
/*add:廣播修改處*/
//預設套接字是關閉廣播的,開啟如下:
int so_brd = 1; //設定為1就可以開啟廣播
setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (void *)&so_brd, sizeof(so_brd));
if((fp = fopen("/Users/app05/Desktop/test.txt", "r")) == NULL)
error_handling("fopen() error");
while (!feof(fp)) //如果檔案結束,則返回非0值,否則返回0
{
fgets(buf, BUF_SIZE, fp);
sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr *)&mul_adr, sizeof(mul_adr));
sleep(1); //只是為了加個傳輸資料時間間隔,沒有特殊意義
}
fclose(fp);
close(send_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(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
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
//
// main.cpp
// hello_client
//
// Created by app05 on 15-9-7.
// Copyright (c) 2015年 app05. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, const char * argv[]) {
int recv_sock;
int str_len;
char buf[BUF_SIZE];
struct sockaddr_in adr;
//struct ip_mreq join_adr; //多播組結構體
if(argc != 2)
{
printf("Usage : %s <GroupIp> <Port> \n", argv[0]);
exit(1);
}
recv_sock = socket(PF_INET, SOCK_DGRAM, 0);
memset(&adr, 0, sizeof(adr));
adr.sin_family = AF_INET;
adr.sin_addr.s_addr = htonl(INADDR_ANY);
adr.sin_port = htons(atoi(argv[1]));
if(bind(recv_sock, (struct sockaddr *)&adr, sizeof(adr)) == -1)
error_handling("bind() error");
//加入多播組
//join_adr.imr_multiaddr.s_addr = inet_addr(argv[1]);
//join_adr.imr_interface.s_addr = htonl(INADDR_ANY);
//setsockopt(recv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&join_adr, sizeof(join_adr));
while (1) {
str_len = recvfrom(recv_sock, buf, BUF_SIZE - 1, 0, NULL, 0);//只需要多播組IP地址,不關心自己主機地址
if(str_len < 0)
break;
buf[str_len] = 0;
fputs(buf, stdout);
}
close(recv_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(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
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65