读书笔记:在局域网中实现多播功能

妖精宝蓝苏洙

妖精宝蓝苏洙

2016-02-19 13:58

下面,图老师小编带您去了解一下读书笔记:在局域网中实现多播功能,生活就是不断的发现新事物,get新技能~

  最近一直在看《Unix网络编程》这本书,觉得这本书很适合初学socket编程的人(比如说我自己 ^_^ )。我一直对于多播的实现比较模糊,在看了书上的多播部分的介绍,才发现在程序中实现一个基本的多播功能是如此简单。

  在这里我不想照本宣科的大说什么理论,概念的东东,我的目的是说明在我们的代码中如何实现多播功能。

  开发环境: VC 6.0(sp5), 使用winsock2(ws2_32.lib)
  测试环境: 三台机器位于两个不同的AD域中,所有机器都是windows 2000(SP4)的操作系统。 sz09和kenfilweb4位于域kenfilszwin2k, kenfil-sz18是域sz18-domain域的一台DC。

  对于局域网来说,我们可以使用的多播地址为224.0.0.0-224.0.0.255(想知道为什么?看看书吧。:-) )

  多播是通过设置套接口(socket, 来自书上的翻译)选项来实现的,这个套接口必须是一个UDP的套接口

(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)

  IP_ADD_MEMBERSHIP: 加入一个多播组
  IP_DROP_MEMBERSHIP: 离开一个多播组
  IP_MULTICAST_IF: 指定外出多播数据报的外出接口
  IP_MULTICAST_TTL: TTL数
 IP_MULTICAST_LOOP: 是否禁止回馈,我的理解是一台机器是否可以接收到自己发送的多播数据报在设置IP_ADD_MEMBERSHIP和IP_DROP_MEMBERSHIP选项的时候,我们需要用到ip_mreq结构, 要使用此结构,你必须include , 并确保此include位于include 之下

  程序功能:程序读取用户输入的行发送到多播组,加入多播组的任何客户端应该显示从多播组中读到的数据。

  实现代码如下:

  //Project Setting - C/C++ - Code Generation - 确认选中"Debug Multithreaded"

  #include
  #include //注意这里的include文件顺序
  #include
  #include //_beginthread要求

  #pragma comment(lib, "ws2_32.lib")

  using namespace std;

const char* MULTICAST_IP = "224.0.0.99"; //多播组地址
  const int MULTICAST_PORT = 2002; //多播组端口

  const int BUFFER_SIZE = 1024;

  void do_send(void* arg); //读取用户输入并发送到多播组线程函数
  void do_read(void* arg); //读物多播组数据函数

  int main()
  {
  WSAData wsaData;

  if( WSAStartup(MAKEWORD(2,2), &wsaData) != 0 )
  {
  cout"Error in WSAStartup" return 0;
  }

  SOCKET server;
  server = socket(AF_INET, SOCK_DGRAM, 0); //创建一个UDP套接口
  cout"create socket: "
  int ret ;

  const int on = 1; //允许程序的多个实例运行在同一台机器上
  ret = setsockopt(server, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
  if( ret == SOCKET_ERROR )
  {
  WSACleanup();

  cout"Error in setsockopt(SO_REUSEADDR): " return 0;
  }

  const int routenum = 10;
  ret = setsockopt(server,IPPROTO_IP,IP_MULTICAST_TTL,
  (char*)&routenum,sizeof(routenum));
  if( ret == SOCKET_ERROR )
  {
  WSACleanup();
  cout"Error in setsockopt(IP_MULTICAST_TTL): " return 0;
  }

  const int loopback = 0; //禁止回馈
  ret = setsockopt(server,IPPROTO_IP,IP_MULTICAST_LOOP,
  (char*)&loopback,sizeof(loopback));
  if( ret == SOCKET_ERROR )
  {
  WSACleanup();

  cout"Error in setsockopt(IP_MULTICAST_LOOP): " return 0;
  }

  sockaddr_in local;
  memset(&local, 0, sizeof(local));
  local.sin_family = AF_INET;
  local.sin_port = htons(MULTICAST_PORT);
  local.sin_addr.S_un.S_addr = INADDR_ANY;

  ret = bind(server, (sockaddr*)(&local), sizeof(local));
  if( ret == SOCKET_ERROR )
  {
  WSACleanup();

  cout"Error in bind: " return 0;
  }

  ip_mreq mreq;
  memset(&mreq, 0, sizeof(mreq));
  mreq.imr_interface.S_un.S_addr = INADDR_ANY;
  mreq.imr_multiaddr.S_un.S_addr = inet_addr(MULTICAST_IP);

  //加入一个多播组
  ret = setsockopt(server,IPPROTO_IP,IP_ADD_MEMBERSHIP,
  (char*)&mreq,sizeof(mreq));
  if( ret == SOCKET_ERROR )
  {
  WSACleanup();
  cout"Error in setsockopt(IP_ADD_MEMBERSHIP): " return 0;
  }

  //创建了两个线程,一个读用户输入并发送,一个读多播组数据
  HANDLE hHandle[2];
  hHandle[0] = (HANDLE)_beginthread(do_send,0,(void*)server);
  hHandle[1] = (HANDLE)_beginthread(do_read,0,(void*)server);

(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)

  //如果用户输入结束,程序就终止了
  WaitForSingleObject(hHandle[0], INFINITE);

  WSACleanup();

  return 0;
  }

  void do_send(void* arg)
  {
  SOCKET server = (SOCKET)arg;

  char sendline[BUFFER_SIZE+1];

  sockaddr_in remote;
  memset(&remote, 0, sizeof(remote));
  remote.sin_addr.s_addr = inet_addr ( MULTICAST_IP );
  remote.sin_family = AF_INET ;
  remote.sin_port = htons(MULTICAST_PORT);

  for(;;) //读取用户输入知道用户输入"end"
  {
  cin.getline(sendline, BUFFER_SIZE);

  if(strncmp(sendline,"end",3)==0)
  break;

  //发送用户输入的数据到多播组
  sendto(server, sendline, strlen(sendline), 0, (sockaddr*)(&remote), sizeof(remote));
  }

  cout"do_send end..."}

  void do_read(void* arg)
  {
  SOCKET server = (SOCKET)arg;

  char buf[BUFFER_SIZE+1];
  int ret;

  sockaddr_in client;
  int clientLen;

  for(;;) //一直读取知道主线程终止
  {
  clientLen = sizeof(client);
  memset(&client, 0, clientLen);

  ret = recvfrom(server, buf, BUFFER_SIZE, 0, (sockaddr*)(&clientLen), &clientLen);
  if ( ret == 0) //do_read在用户直接回车发送了一个空字符串
  {
  continue;
  }
  else if( ret == SOCKET_ERROR )
  {
  if( WSAGetLastError() == WSAEINTR ) //主线程终止recvfrom返回的错
  break;

  cout"Error in recvfrom: " break ;
  }
  buf[ret] = '

展开更多 50%)
分享

猜你喜欢

读书笔记:在局域网中实现多播功能

编程语言 网络编程
读书笔记:在局域网中实现多播功能

利用TXT文件在局域网中聊天

电脑网络
利用TXT文件在局域网中聊天

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

Essential .NET读书笔记

电脑网络
Essential .NET读书笔记

局域网中OutlookExpress的设置

办公软件
局域网中OutlookExpress的设置

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

MYSQL权威指南读书笔记

PHP
MYSQL权威指南读书笔记

VB6实现局域网多站点互连手册

编程语言 网络编程
VB6实现局域网多站点互连手册

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

重载函数的应用与深入剖析

重载函数的应用与深入剖析

曾经,我抽过烟 - QQ伤感分组

曾经,我抽过烟 - QQ伤感分组
下拉加载更多内容 ↓