计算机网络课程设计-基于 IP 多播的网络会议程序

目录

前言

1 实验题目

2 实验目的

3 实验内容

3.1 步骤

3.2 关键代码

3.2.1 发送者

3.2.2 接收者

4 实验结果与分析

5 代码

5.1 发送者

5.2 接收者


前言

        本实验为计算机网络课程设计内容,基本上所有代码都是根据指导书给的附录写出来的。有些实验需要实现图形界面,但是出于期末考试压力,我所有实验均是在控制台输入输出的,没有花额外时间去学习qt了,有精力的同学可以自学一下qt实现简单的图形界面。同时,该博客内容为部分报告内容,仅为大家提供参考,请勿直接抄袭。另外,本次实验所用平台是dev c++5.11

        该实验需要配置一下防护墙和网络适配器,如果在操作系统课程设计时安装了vm虚拟机的,最好把两台电脑的vm网络适配器同时开启或者同时关闭。这个实验实际上我只是书上的代码跑了一下,但是因为我当时想去评一下优,而别人想评优的基本上都有界面,我没有,所以我就把这个实验也算上完成的了,拿数量来凑数了,有能力的同学尽力按要求完成做个图形界面

1 实验题目

        实验五 基于 IP 多播的网络会议程序

2 实验目的

        参照附录 5 的局域网 IP 多播程序,设计一个图形界面的网络会议程序(实现文本多播方式即可)。

3 实验内容

3.1 步骤

        (1)初始化 WinSock2.2;

        (2)创建套接字并加入多播组;

        (3)发送者发送多播数据,并监听控制台输入,直到接收到 "QUIT" 命令;

        (4)接收者加入多播组,接收并打印多播数据,直到接收到 "QUIT" 为止。

3.2 关键代码

3.2.1 发送者

        (1)调用WSAJoinLeaf函数加入多播组

if(( sockM = WSAJoinLeaf(sock,(SOCKADDR*)&remote,
		sizeof(remote),NULL,NULL,NULL,NULL,JL_BOTH)) == INVALID_SOCKET) {
		printf("WSAJoinLeaf() failed:%d\n",WSAGetLastError());
		closesocket(sock);
		WSACleanup();
		return -1;
	}

        (2)在发送端主要利用sendto(sockM,(char*)sendbuf,strlen(sendbuf),0,(struct sockaddr*)&remote,sizeof(remote))将数据发送到多播组中

//发送多播数据,当用户在控制台输入"QUIT"时退出。
while(1) {
		printf("SEND : ");
		scanf("%s",sendbuf);
		if( sendto(sockM,(char*)sendbuf,strlen(sendbuf),0,(struct sockaddr*)
		&remote,sizeof(remote))==SOCKET_ERROR) {
			printf("sendto failed with: %d\n",WSAGetLastError());
			closesocket(sockM);
			closesocket(sock);
			WSACleanup();
			return -1;
		}
		memset(sendBuf,'\0',128);
		cout<<sprintf(sendBuf,"Welcome %s to here!",inet_ntoa(remote.sin_addr));
		cout<<"remote:"<<sendBuf<<"\n";
		if(strcmp(sendbuf,"QUIT")==0) break;
		Sleep(500);
	}

3.2.2 接收者

        (1)调用WSAJoinLeaf函数加入多播组

if(( sockM = WSAJoinLeaf(sock,(SOCKADDR*)&remote,sizeof(remote),
		NULL,NULL,NULL,NULL,
		JL_BOTH)) == INVALID_SOCKET) {
		printf("WSAJoinLeaf() failed:%d\n",WSAGetLastError());
		closesocket(sock);
		WSACleanup();
		return -1;
	}

        (2)在接收端主要利用recvfrom(sock,recvbuf,BUFSIZE,0,(struct sockaddr*)&from,&len)函数从多播组中接收数据。

//接收多播数据,当接收到的数据为"QUIT"时退出。
while(1) {
		if(( ret = recvfrom(sock,recvbuf,BUFSIZE,0,
			(struct sockaddr*)&from,&len)) == SOCKET_ERROR) {
			printf("recvfrom failed with:%d\n",WSAGetLastError());
			closesocket(sockM);
			closesocket(sock);
			WSACleanup();
			return -1;
		}
		if( strcmp(recvbuf,"QUIT") == 0 ) break;
		else {
			recvbuf[ret] = '\0';
			printf("RECV:' %s ' FROM <%s> \n",recvbuf,inet_ntoa(from.sin_addr));
		}
	}

4 实验结果与分析

(1)在本机启动发送端加入多播组。

图1.1 发送端加入多播组

(2)在另一台主机上启动接收端加入多播组。

图1.2 接收端加入多播组

(3)在本机的发送端发送“你好,欢迎加入多播组!”,可以在另一台主机的接收端上收到相应的消息。

图1.3 发送端发送信息

图1.4 接收端成功接收到信息

5 代码

5.1 发送者

//sender.cpp
#include<bits/stdc++.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#define MCASTADDR "233.0.0.1" 	//本例使用的多播组地址。
#define MCASTPORT 5150 			//本地端口号。
#define BUFSIZE 1024 			//发送数据缓冲大小。
#pragma comment(lib,"ws2_32")

using namespace std;

int main( int argc,char ** argv) {
	WSADATA wsd;
	struct sockaddr_in remote,local,from;
	SOCKET sock,sockM;
	TCHAR sendbuf[BUFSIZE];
	int len = sizeof( struct sockaddr_in);
	//初始化 WinSock2.2
	if( WSAStartup( MAKEWORD(2,2),&wsd) != 0 ) {
		printf("WSAStartup() failed\n");
		return -1;
	}
	if((sock=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,
	                   WSA_FLAG_MULTIPOINT_C_LEAF|WSA_FLAG_MULTIPOINT_D_LEAF|
	                   WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) {
		printf("socket failed with:%d\n",WSAGetLastError());
		WSACleanup();
		return -1;
	}

	//加入多播组
	remote.sin_family = AF_INET;
	remote.sin_port = htons(MCASTPORT);
	remote.sin_addr.s_addr = inet_addr( MCASTADDR );
	if(( sockM = WSAJoinLeaf(sock,(SOCKADDR*)&remote,
	                         sizeof(remote),NULL,NULL,NULL,NULL,
	                         JL_BOTH)) == INVALID_SOCKET) {
		printf("WSAJoinLeaf() failed:%d\n",WSAGetLastError());
		closesocket(sock);
		WSACleanup();
		return -1;
	}
	char sendBuf[128];
	cout<<sprintf(sendBuf,"Welcome %s to here!",inet_ntoa(local.sin_addr));
	cout<<"local:"<<sendBuf<<"\n";

	memset(sendBuf,'\0',128);
	cout<<sprintf(sendBuf,"Welcome %s to here!",inet_ntoa(remote.sin_addr));
	cout<<"remote:"<<sendBuf<<"\n";

	//发送多播数据,当用户在控制台输入"QUIT"时退出。
	while(1) {
		printf("SEND : ");
		scanf("%s",sendbuf);
		if( sendto(sockM,(char*)sendbuf,strlen(sendbuf),0,(struct sockaddr*)
		           &remote,sizeof(remote))==SOCKET_ERROR) {
			printf("sendto failed with: %d\n",WSAGetLastError());
			closesocket(sockM);
			closesocket(sock);
			WSACleanup();
			return -1;
		}
		memset(sendBuf,'\0',128);
		cout<<sprintf(sendBuf,"Welcome %s to here!",inet_ntoa(remote.sin_addr));
		cout<<"remote:"<<sendBuf<<"\n";
		
		if(strcmp(sendbuf,"QUIT")==0) break;
		Sleep(500);
	}

	closesocket(sockM);
	closesocket(sock);
	WSACleanup();
	return 0;
}

5.2 接收者

//receiver.cpp
#include<bits/stdc++.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#define MCASTADDR "233.0.0.1" //本例使用的多播组地址。
#define MCASTPORT 5150 //绑定的本地端口号。
#define BUFSIZE 1024 //接收数据缓冲大小。
#pragma comment(lib,"ws2_32")

using namespace std;
int main( int argc,char ** argv) {
	WSADATA wsd;
	struct sockaddr_in local,remote,from;
	SOCKET sock,sockM;
	TCHAR recvbuf[BUFSIZE];
	/*struct ip_mreq mcast; // Winsock1.0 */

	int len = sizeof( struct sockaddr_in);
	int ret;
	//初始化 WinSock2.2
	if( WSAStartup( MAKEWORD(2,2),&wsd) != 0 ) {
		printf("WSAStartup() failed\n");
		return -1;
	}
	/*
	创建一个 SOCK_DGRAM 类型的 SOCKET
	其中,WSA_FLAG_MULTIPOINT_C_LEAF 表示 IP 多播在控制面层上属于
	"无根"类型;
	WSA_FLAG_MULTIPOINT_D_LEAF 表示 IP 多播在数据面层上属于"无根",
	有关控制面层和
	数据面层有关概念请参阅 MSDN 说明。
	*/
	if((sock=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,
	                   WSA_FLAG_MULTIPOINT_C_LEAF|WSA_FLAG_MULTIPOINT_D_LEAF|
	                   WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) {
		printf("socket failed with:%d\n",WSAGetLastError());
		WSACleanup();
		return -1;
	}
	//将 sock 绑定到本机某端口上。
	local.sin_family = AF_INET;
	local.sin_port = htons(MCASTPORT);
	local.sin_addr.s_addr = INADDR_ANY;
	if( bind(sock,(struct sockaddr*)&local,sizeof(local)) == SOCKET_ERROR ) {
		printf( "bind failed with:%d \n",WSAGetLastError());
		closesocket(sock);
		WSACleanup();
		return -1;
	}
	//加入多播组
	remote.sin_family = AF_INET;
	remote.sin_port = htons(MCASTPORT);
	remote.sin_addr.s_addr = inet_addr( MCASTADDR );
	/* Winsock1.0 */
	/*
	mcast.imr_multiaddr.s_addr = inet_addr(MCASTADDR);
	mcast.imr_interface.s_addr = INADDR_ANY;
	if( setsockopt(sockM,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&mcast,

	sizeof(mcast)) == SOCKET_ERROR)
	{
	printf("setsockopt(IP_ADD_MEMBERSHIP) failed:%d\n",WSAGetLastError());
	closesocket(sockM);
	WSACleanup();
	return -1;
	}
	*/
	/* Winsock2.0*/
	if(( sockM = WSAJoinLeaf(sock,(SOCKADDR*)&remote,sizeof(remote),

	                         NULL,NULL,NULL,NULL,
	                         JL_BOTH)) == INVALID_SOCKET) {
		printf("WSAJoinLeaf() failed:%d\n",WSAGetLastError());
		closesocket(sock);
		WSACleanup();
		return -1;
	}
	char sendBuf[128];
	cout<<sprintf(sendBuf,"Welcome %s to here!",inet_ntoa(local.sin_addr));
	cout<<"local:"<<sendBuf<<"\n";

	memset(sendBuf,'\0',128);
	cout<<sprintf(sendBuf,"Welcome %s to here!",inet_ntoa(remote.sin_addr));
	cout<<"remote:"<<sendBuf<<"\n";
	//接收多播数据,当接收到的数据为"QUIT"时退出。
	while(1) {
		if(( ret = recvfrom(sock,recvbuf,BUFSIZE,0,

		                    (struct sockaddr*)&from,&len)) == SOCKET_ERROR) {
			printf("recvfrom failed with:%d\n",WSAGetLastError());
			closesocket(sockM);
			closesocket(sock);
			WSACleanup();
			return -1;

		}
		if( strcmp(recvbuf,"QUIT") == 0 ) break;
		else {
			recvbuf[ret] = '\0';
			printf("RECV:' %s ' FROM <%s> \n",recvbuf,inet_ntoa(from.sin_addr));
		}
	}

	closesocket(sockM);
	closesocket(sock);
	WSACleanup();
	return 0;
}

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值