程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> vc教程 >> 讀書筆記:在局域網中實現多播功能

讀書筆記:在局域網中實現多播功能

編輯:vc教程
 最近一直在看《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的套接口

  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);

  //如果用戶輸入結束,程序就終止了
  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] = '';
  cout<<"received: "< }

  cout<<"do_read end..."<}

  當然上面的代碼如果應用到實際的程序中還需要作更多的工作,不過實現多播功能真的很簡單,不是嗎 :-)

  我只是剛剛才開始學習網絡編程方面的東東,上面的代碼如果你認為有什麼問題,請直接發email給我。

  1. 上一頁:
  2. 下一頁:
欄目導航
Copyright © 程式師世界 All Rights Reserved