设为首页 加入收藏

TOP

记一次奇葩的计算机网络作业(一)
2017-10-13 10:22:17 】 浏览:10312
Tags:一次 奇葩 计算机网络 作业

前天考完了计算机网络,这学期只剩下数据库和组成原理两门考试了。开通博客以来也一直没有写什么东西,正好想起来之前计算机网络课老师流过一个比较奇葩的作业,就整理一下贴上来吧。以后慢慢将自己从大一以来的编程笔记贴到博客上来,笔记主要是内核驱动方面的内容。

当时计算机网络每两周有一节讨论课。老师会留一些题目让学生选做,看样子题目都是老师自己想出来的。有一次一组题目里有一条是QQ群聊中多播IP如何获取,我就选了这条,因为我想QQ群聊怎么可能用的是多播。一是因为使用组播的话好多功能无法实现,比如上传群文件。二是因为这不利于腾讯对群消息的监控。

在网上也有很多人对这个问题进行讨论。通过筛选我确定了三个最有可能的方法。一是在群里指定几个网速快的用户作为Server将消息转发,比如指定群中有100人,指定五个人作为Server,每个用户发送的消息会发给这五个人,在由他们向其他人转发。这个方法管理起来可能会比较麻烦。而是服务器为每个群维护一个用户列表,群消息发送给服务器,由服务器向每个人转发。这个方法对服务器开销很大。三是P2P和服务器转发相结合。

群聊具体使用的什么机制只要腾讯不公开我们就无法精确了解。但是否定某些可能的机制还是有戏的,接下来我要做的就是否定老师说的使用组播了。

组播的具体原理就不在详细的介绍了。我们使用setsockopts函数可以加入或离开某个组。加入某个组之后就可以接受到这个组内的消息。而调用sendto函数,将第三参数设置为组的地址,就可以向这个组中发送消息。向组内发送消息不用加入到这个组中。

我写了两套组播的小程序作为参照。每套包含两个组播发送方与组播接受方。这两套程序的发送方与接收方代码里除了组播地址与绑定的端口不同外,其他都一样。也就是每套程序就是一个组,一个组里有两个用户发送接收消息。两个组的地址分别为234.5.6.7和234.5.6.8。使用两台位于同一WIFI的计算机进行测试,计算机A打开两个接收程序,分别监听着两个组中的消息。计算机B用于发送。B中运行抓包软件进行抓包分析。

接受消息的代码为

 1 #include <winsock2.h>
 2 #pragma comment(lib, "WS2_32")
 3 
 4 #include <stdio.h>
 5 #include <windows.h>
 6 #include <Ws2tcpip.h>
 7 
 8 
 9 class CInitSock
10 {
11 public:
12     CInitSock();
13     ~CInitSock();
14 };
15 
16 inline CInitSock::CInitSock()
17 {
18     // 初始化WS2_32.dll
19     WSADATA wsaData;
20     WORD sockVersion = MAKEWORD(2, 2);
21     if(::WSAStartup(sockVersion, &wsaData) != 0)
22     {
23         exit(0);
24     }
25 }
26 
27 inline CInitSock::~CInitSock()
28 {
29     ::WSACleanup();    
30 }
31 
32 
33 
34 
35 
36 // 初始化Winsock库
37 CInitSock theSock;
38 
39 void main()
40 {
41     SOCKET s = ::socket(AF_INET, SOCK_DGRAM, 0);
42 
43     // 允许其它进程使用绑定的地址
44     BOOL bReuse = TRUE;
45     ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&bReuse, sizeof(BOOL));
46 
47 
48     // 绑定到4567端口
49     sockaddr_in si;
50     si.sin_family = AF_INET;
51     si.sin_port = ::ntohs(4567);
52     si.sin_addr.S_un.S_addr = INADDR_ANY;
53     ::bind(s, (sockaddr*)&si, sizeof(si));
54     
55     // 加入多播组
56     ip_mreq    mcast;
57     mcast.imr_interface.S_un.S_addr = INADDR_ANY;
58     mcast.imr_multiaddr.S_un.S_addr = ::inet_addr("234.5.6.7");  // 多播地址为234.5.6.7
59     ::setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast));
60 
61 
62     // 接收多播组数据
63     printf(" 开始接收多播组234.5.6.7上的数据... \n");
64     char buf[1280];
65     int nAddrLen = sizeof(si);
66     while(TRUE)
67     {
68         int nRet = ::recvfrom(s, buf, strlen(buf), 0, (sockaddr*)&si, &nAddrLen);
69         if(nRet != SOCKET_ERROR)
70         {
71             buf[nRet] = '\0';
72             printf(buf);
73         }
74         else
75         {
76             int n = ::WSAGetLastError();
77             break;
78         }
79     }
80 }

 

 

  发送消息的代码为

 1 #include <winsock2.h>
 2 #pragma comment(lib, "WS2_32")    // 链接到WS2_32.lib
 3 #include <stdio.h>
 4 #include <Ws2tcpip.h>
 5 
 6 
 7 class CInitSock        
 8 {
 9 public:
10     CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)
11     {
12         // 初始化WS2_32.dll
13         WSADATA wsaData;
14         WORD sockVersion = MAKEWORD(minorVer, majorVer);
15         if(::WSAStartup(sockVersion, &wsaData) != 0)
16         {
17             exit(0);
18         }
19     }
20     ~CInitSock()
21     {    
22         ::WSACleanup();    
23     }
24 };
25 
26 
27 CInitSock initSock;        // 初始化Winsock库
28 int main()
29 {
30     // 创建套节字
31     SOCKET sSend = ::socket(AF_INET, SOCK_DGRAM, 0);
32     if(sSend == INVALID_SOCKET)
33     {
34         printf("Failed socket() \n");
35         return 0;
36     }
37 
38     // 允许其它进程使用绑定的地址
39     BOOL bReuse = TRUE;
40     ::setsockopt(sS
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇当年只会C# 所以写C++就成这样了.. 下一篇阶乘0问题

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目