目的
(1)在掌握IP多播的基本概念和工作原理的基础上,进行多播编程,实现多播通信;
(2)在掌握广播的基本概念和工作原理的基础上,进行广播播编程,实现广播通信;
内容
(1)编写一对用于发送和接收信息的IP多播程序,其中: 发送端可向该多播组广播文件中保存的文本信息,接收端可接收传递到该多播组的文本信息。
(2)编写一对用于发送和接收信息的IP多播程序,其中:
发送端可向该多播组广播使用者从键盘输入的即时消息,接收端可接收传递到该多播组的即时消息。
(3)编写一对用于发送和接收信息的广播程序,其中: 发送端可向特定网络广播文件中保存的文本信息,接收端可接收传递到该网络的文本信息。
(4)编写一对用于发送和接收信息的广播程序,其中: 发送端可向特定网络广播使用者从键盘输入的即时消息,接收端可接收传递到该网络的即时消息。
源代码及结果
(1)编写一对用于发送和接收信息的IP多播程序,其中: 发送端可向该多播组广播文件中保存的文本信息,接收端可接收传递到该多播组的文本信息。
//发送端(linux环境下)
//news_sender.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define TTL 64
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, 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);
}
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]); // Multicast IP
mul_adr.sin_port=htons(atoi(argv[2])); // Multicast Port
setsockopt(send_sock, IPPROTO_IP,
IP_MULTICAST_TTL, (void*)&time_live, sizeof(time_live));
if((fp=fopen("news.txt", "r"))==NULL)//打开文件
error_handling("fopen() error");
while(!feof(fp)) /* Broadcasting */
{
fgets(buf, BUF_SIZE, fp);//从文件中读取字符
sendto(send_sock, buf, strlen(buf),
0, (struct sockaddr*)&mul_adr, sizeof(mul_adr));
sleep(2);
}
fclose(fp);//关闭文件
close(send_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
//接收端(linux环境下)
//news_receiver.c
#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, 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);
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);
}
测试结果:
(2)编写一对用于发送和接收信息的IP多播程序,其中: 发送端可向该多播组广播使用者从键盘输入的即时消息,接收端可接收传递到该多播组的即时消息。
//发送端(linux环境下)
//sender.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define TTL 64
#define BUF_SIZE 30
void error_handling(char *message);
int main(int argc, char *argv[])
{
int send_sock;
struct sockaddr_in mul_adr;
int time_live=TTL;
char buf[BUF_SIZE];
if(argc!=3){
printf("Usage : %s <GroupIP> <PORT>\n", argv[0]);
exit(1);
}
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]); // Multicast IP
mul_adr.sin_port=htons(atoi(argv[2])); // Multicast Port
setsockopt(send_sock, IPPROTO_IP,
IP_MULTICAST_TTL, (void*)&time_live, sizeof(time_live));
while(1) /* Broadcasting */
{
fputs("please enter:",stdout);
fgets(buf, BUF_SIZE, stdin);//输入字符串
sendto(send_sock, buf, strlen(buf),
0, (struct sockaddr*)&mul_adr, sizeof(mul_adr));
}
close(send_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
//接收端(linux环境下)
//receiver.c
#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, 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);
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);
}
测试结果:
(3)编写一对用于发送和接收信息的广播程序,其中: 发送端可向特定网络广播文件中保存的文本信息,接收端可接收传递到该网络的文本信息。
//发送端(linux环境下)
//news_sender_brd.c
#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, char *argv[])
{
int send_sock;
struct sockaddr_in broad_adr;
FILE *fp;
char buf[BUF_SIZE];
int so_brd=1;//对变量进行初始化以将SO_BROADCAST选项信息改为1
if(argc!=3) {
printf("Usage : %s <Boradcast IP> <PORT>\n", argv[0]);
exit(1);
}
send_sock=socket(PF_INET, SOCK_DGRAM, 0);
//广播地址
memset(&broad_adr, 0, sizeof(broad_adr));
broad_adr.sin_family=AF_INET;
broad_adr.sin_addr.s_addr=inet_addr(argv[1]);
broad_adr.sin_port=htons(atoi(argv[2]));
//
setsockopt(send_sock, SOL_SOCKET,
SO_BROADCAST, (void*)&so_brd, sizeof(so_brd)); //将SO_BROADCAST选项设置为so_brd变量中的值1
if((fp=fopen("news.txt", "r"))==NULL)//打开文件
error_handling("fopen() error");
while(!feof(fp))
{
fgets(buf, BUF_SIZE, fp);
sendto(send_sock, buf, strlen(buf),
0, (struct sockaddr*)&broad_adr, sizeof(broad_adr));
sleep(2);
}
close(send_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
//接收端(linux环境下)
//news_receiver_brd.c
#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, char *argv[])
{
int recv_sock;
struct sockaddr_in adr;
int str_len;
char buf[BUF_SIZE];
if(argc!=2) {
printf("Usage : %s <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");
while(1)
{
str_len=recvfrom(recv_sock, buf, BUF_SIZE-1, 0, NULL, 0);
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);
}
测试结果:
(4)编写一对用于发送和接收信息的广播程序,其中: 发送端可向特定网络广播使用者从键盘输入的即时消息,接收端可接收传递到该网络的即时消息。
//发送端(linux环境下)
//sender_brd.c
#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, char *argv[])
{
int send_sock;
struct sockaddr_in broad_adr;
char buf[BUF_SIZE];
int so_brd=1;//对变量进行初始化以将SO_BROADCAST选项信息改为1
if(argc!=3) {
printf("Usage : %s <Boradcast IP> <PORT>\n", argv[0]);
exit(1);
}
send_sock=socket(PF_INET, SOCK_DGRAM, 0);
//广播地址
memset(&broad_adr, 0, sizeof(broad_adr));
broad_adr.sin_family=AF_INET;
broad_adr.sin_addr.s_addr=inet_addr(argv[1]);
broad_adr.sin_port=htons(atoi(argv[2]));
//
setsockopt(send_sock, SOL_SOCKET,
SO_BROADCAST, (void*)&so_brd, sizeof(so_brd)); //将SO_BROADCAST选项设置为so_brd变量中的值1
while(1)
{
fputs("please enter:",stdout);
fgets(buf, BUF_SIZE, stdin);
sendto(send_sock, buf, strlen(buf),
0, (struct sockaddr*)&broad_adr, sizeof(broad_adr));
sleep(2);
}
close(send_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
//接收端(linux环境下)
//receiver_brd.c
#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, char *argv[])
{
int recv_sock;
struct sockaddr_in adr;
int str_len;
char buf[BUF_SIZE];
if(argc!=2) {
printf("Usage : %s <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");
while(1)
{
str_len=recvfrom(recv_sock, buf, BUF_SIZE-1, 0, NULL, 0);
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);
}
测试结果:
拓展
了解了广播与多播的作用,运用原理测试了聊天室功能
多播聊天:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 100
#define TTL 64
void error_handling(char *message);
int main(int argc, char *argv[])
{
int recv_sock,send_sock;
struct sockaddr_in adr;
struct sockaddr_in mul_adr;
int time_live=TTL;
int str_len,len;
char buf[BUF_SIZE];
char name[10]; //用户名字
pid_t pid;
struct ip_mreq join_adr;
//名字赋值
len = strlen(argv[3]);
memcpy(name,argv[3],len);
memcpy(name+len,":",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]));
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]); // Multicast IP
mul_adr.sin_port=htons(atoi(argv[2])); // Multicast Port
setsockopt(send_sock, IPPROTO_IP,
IP_MULTICAST_TTL, (void*)&time_live, sizeof(time_live));
if(bind(recv_sock, (struct sockaddr*)&adr, sizeof(adr))==-1)
error_handling("bind() error");
pid = fork();//创建子进程,子进程用来接收数据,父进程用来发送数据
if(pid==0)
{
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);
if(str_len<0)
break;
buf[str_len]=0;
fputs(buf, stdout);
}
}
else
{
while(1){
fgets(buf+len+1,sizeof(buf)-len-1,stdin);//输入需要发送的数据
memcpy(buf,name,len+1);//加上客户的名字一起广播发送出去
sendto(send_sock, buf, strlen(buf),
0, (struct sockaddr*)&mul_adr, sizeof(mul_adr));
sleep(2);
}
}
close(send_sock);
close(recv_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
测试结果:
同一局域网下的两台linux(ubantu和kali)
广播聊天:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 100
void error_handling(char *message);
int main(int argc, char *argv[])
{
int recv_sock,send_sock;
struct sockaddr_in adr;
int str_len,len;
char buf[BUF_SIZE];
char name[10]; //用户名字
struct sockaddr_in broad_adr;
int so_brd=1;
pid_t pid;
//名字赋值
len = strlen(argv[3]);
memcpy(name,argv[3],len);
memcpy(name+len,":",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]));
send_sock=socket(PF_INET, SOCK_DGRAM, 0);
memset(&broad_adr, 0, sizeof(broad_adr));
broad_adr.sin_family=AF_INET;
broad_adr.sin_addr.s_addr=inet_addr(argv[1]);
broad_adr.sin_port=htons(atoi(argv[2]));
setsockopt(send_sock, SOL_SOCKET,
SO_BROADCAST, (void*)&so_brd, sizeof(so_brd));
if(bind(recv_sock, (struct sockaddr*)&adr, sizeof(adr))==-1)
error_handling("bind() error");
pid = fork();//创建子进程,子进程用来接收数据,父进程用来发送数据
if(pid==0)
{
while(1){
str_len=recvfrom(recv_sock, buf, BUF_SIZE-1, 0, NULL, 0);
if(str_len<0)
break;
buf[str_len]=0;
fputs(buf, stdout);
}
}
else
{
while(1){
fgets(buf+len+1,sizeof(buf)-len-1,stdin);//输入需要发送的数据
memcpy(buf,name,len+1);//加上客户的名字一起广播发送出去
sendto(send_sock, buf, strlen(buf),
0, (struct sockaddr*)&broad_adr, sizeof(broad_adr));
}
}
close(send_sock);
close(recv_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
测试结果:
同一局域网下的两台linux(ubantu和kali)
此程序可以多台统一网段中的电脑进行通信,接受和发送数据在同一程序中,子进程负责进行接收数据,父进程负责发送数据,这样就能既接收数据又能发送数据。