计算机网络课程设计之基于 IP 多播的网络会议程序
前言
本實驗難點在于環境的配置,尤其是多網卡配置,經過查閱資料和多次小伙伴們測試,最后終于找到問題的根源
問題分析和配置主要放在實驗結果與分析欄中
結尾附上指導書的IP多播源碼
白嫖容易,創作不易,本文原創,轉載請注明!!!
源碼和可運行程序:
鏈接:https://pan.baidu.com/s/1A9KctmpP2JJgyW2wLrehIg
提取碼:Lin2
計算機網絡課程設計:
計算機網絡課程設計之網絡聊天程序的設計與實現
計算機網絡課程設計之Tracert與Ping程序設計與實現
計算機網絡課程設計之基于 IP 多播的網絡會議程序
計算機網絡課程設計之網絡嗅探器的設計與實現
計算機網絡課程設計之電子郵件客戶端程序設計與實現
計算機網絡課程設計之TELNET 終端設計與實現
計算機網絡課程設計之網絡代理服務器的設計與實現
計算機網絡課程設計之簡單 Web Server 程序的設計與實現
Qt入門系列:
Qt學習之C++基礎
Qt學習之Qt安裝
Qt學習之Qt基礎入門(上)
Qt學習之Qt基礎入門(中)
Qt學習之Qt基礎入門(下)
創作不易,整個課程設計程序3000多行代碼,所有實驗都寫在了一個程序中,時間有限,能力不足,轉載望注明!!!
本文鏈接
個人博客:https://ronglin.fun/archives/268
PDF鏈接:見博客網站
CSDN: https://blog.csdn.net/RongLin02/article/details/122510355
實驗題目
基于 IP 多播的網絡會議程序
實驗目的
參照附錄 3 的局域網 IP 多播程序,設計一個圖形界面的網絡會議程序(實現文本多播方式即可)
總體設計
(含背景知識或基本原理與算法、或模塊介紹、設計步驟等)
本題的代碼主要根據指導書的代碼改編。
發送方
發送方重點代碼就是加入多播組
//創建套接字sock=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_MULTIPOINT_C_LEAF| WSA_FLAG_MULTIPOINT_D_LEAFWSA_FLAG_OVERLAPPED); //加入多播組remote.sin_family = AF_INET;remote.sin_port = htons(MCASTPORT);remote.sin_addr.s_addr = inet_addr( MCASTADDR );sockM = WSAJoinLeaf(sock,(SOCKADDR*)&remote,sizeof(remote),NULL,NULL,NULL,NULL,JL_BOTH)) == INVALID_SOCKET);之后就用sendto方法發送數據即可
接收方
接收方主要是監聽對應的地址和端口
sock=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_MULTIPOINT_C_LEAF|WSA_FLAG_MULTIPOINT_D_LEAF|WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET);//將 sock 綁定到本機某端口上。local.sin_family = AF_INET;local.sin_port = htons(MCASTPORT);local.sin_addr.s_addr = INADDR_ANY;bind(sock,(struct sockaddr*)&local,sizeof(local));//加入多播組remote.sin_family = AF_INET;remote.sin_port = htons(MCASTPORT);remote.sin_addr.s_addr = inet_addr( MCASTADDR );/* Winsock2.0*/sockM = WSAJoinLeaf(sock,(SOCKADDR*)&remote,sizeof(remote),NULL,NULL,NULL,NULL,JL_BOTH));之后接收方用recvfrom方法即可收到數據
部分背景知識
并不是所有的協議都支持多播通信,對 Win32 平臺而言,僅兩種可從 WinSock 內訪問的協議(IP/ATM)才提供了對多播通信的支持。因通常通信應用都建立在 TCP/IP 協議之上的,所以本文只針對 IP 協議來探討多播通信技術。
IP 采用 D 類地址來支持多播。當一個進程向一個 D 類地址發送分組時,會盡最大的努力將它送給小組的所有成員,但不能保證全部送到。
D 類 I P地址范圍在 224.0.0.0 到 239.255.255.255 之間。
部分永久地址說明
多播由特殊的多播路由器來實現,多播路由器同時也可以是普通路由器。各個多播路由器每分鐘發送一個硬件多播信息給子網上的主機(目的地址為 224.0.0.1),要求它們報告其進程當前所屬的是哪一組,各主機將它感興趣的 D 類地址返回。這些詢問和響應分組使用 IGMP(Internet group management protocol),它大致類似于 ICMP。它只有兩種分組:詢問和響應,都有一個簡單的固定格式,其中有效載荷字段的第一個字段是一些控制信息,第二字段是一個 D 類地址,在 RFC1112 中有詳細說明。
詳細設計
(含主要的數據結構、程序流程圖、關鍵代碼等)
界面如下
主要是一個大的部分用來顯示數據交互,然后讓用戶輸入多播地址,注意根據背景知識,多播地址應為D類IP地址,然后端口無所謂,端口需要注意,發送者的端口要和接收者的端口一致,但是如果同一臺主機又作為發送者又作為接收者的話,兩個身份的端口是可以不同的。
換言之,就是接收者只會接收到它自己監聽的端口數據,發送者也只會發送數據給對應的端口。
這和TCP連接不同,TCP連接一個客戶端既能發送也能接受,但是多播不一樣,可以只有發送和接受的單一功能。
為了實現多播,我將發送者和接受者的端口設置為同一個,表示既發送又接受
同時多播也用一個子線程,因為要監聽接受數據,這是一個阻塞式的方法
同時提供一個檢測ip合法的一個方法
然后把所有的功能寫入了run()方法
實驗結果與分析
明明代碼是對的,為什么就是收不到數據!!!
這里提供一些思路。
首先提供一個指令,打開CMD,輸入這條指令
可以看到,我們設置的224.1.0.1多播地址在網卡接口 19: 以太網上
然后打開電腦的設置->網絡和Internet->更改適配器選項,然后彈出來一個界面
把自己不需要的網卡給禁了,然后,雙擊自己連接局域網的網卡,我這里就是以太網(網線)
點擊詳細信息,然后看到IPV4地址然后在代碼中,加入多播組的Socket需要是這個地址
然后把主機的防火墻關閉,關閉的方式網上有很多的方法,這里不再說明。
最后說明的一點就是,自己設置的多播地址一定要在連接局域網的網卡上轉發通過netsh interface ipv4 show joins可以查看
然后就是結果展示,找到另外一名小伙伴,讓他也加入多播地址(運行的程序的種類可以不同),然后輸入相同的多播地址和端口,設置好對應的本地網卡地址,然后就可以愉快的玩耍了。
小伙伴的電腦顯示
小結與心得體會
對于IP多播有了更深的理解,同時有了一種局域網相互交換數據的思路,同時可以利用IP多播可以設置一個多人聊天室,類似于飛秋的多人聊天功能,在局域網上面學到了很多知識。
=w=
附多播源碼
sender源碼
#include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #include <stdlib.h> #define MCASTADDR "224.1.0.1" //本例使用的多播組地址。 #define MCASTPORT 23333 //綁定的本地端口號。 #define BUFSIZE 1024 //接收數據緩沖大小。 #pragma comment(lib,"ws2_32") 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.2if( 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;} //接收多播數據,當接收到的數據為"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; }receiver源碼
#include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #include <stdlib.h> #define MCASTADDR "224.1.0.1" //本例使用的多播組地址。 #define MCASTPORT 23333 //綁定的本地端口號。 #define BUFSIZE 1024 //接收數據緩沖大小。 #pragma comment(lib,"ws2_32") 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.2if( 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;} //接收多播數據,當接收到的數據為"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; }總結
以上是生活随笔為你收集整理的计算机网络课程设计之基于 IP 多播的网络会议程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: flex 左右布局_面试必考点:前端布局
- 下一篇: 【python基础】window下pyt