用Socket在局域网内进行广播

来源:互联网 发布:手机淘宝店铺首页红包 编辑:程序博客网 时间:2024/05/17 22:12

服务器和客户机采用Socket编程。 
问题1:服务器进入侦听状态,但是此时客户端并不知道服务器的地址。我该如何做? 

问题2:我想使客户端先发出一个广播,服务器接受广播后给客户机发送自己的Ip等信息。 
接着再建立Socket通讯。这样对吗? 

问题3:是不是进行广播必须是数据报SOCK_DGRAM    

问题4:是不是通讯的双方必须都是数据流或数据报?如果服务器是数据流SOCK_STREAM套接字,而客户机是数据报套接字就不能够通讯? 

1、用广播(或组播)方式,客户端不需道服务器的地址,初始化时用程序建立一个新的广播地址。 
2、用广播(或组播)方式,可直接收发数据。不用侦听。 
3、是; 
4、只要是数据就行。 
例子: 

[cpp] view plaincopy
  1. //   MSGSocket.cpp   :   implementation   file   
  2. //   
  3.   
  4. #include   "stdafx.h "   
  5. //#include   "AV8Rcvr.h "   
  6. #include   "MSGSocket.h "   
  7.   
  8. #ifdef   _DEBUG   
  9. #define   new   DEBUG_NEW   
  10. #undef   THIS_FILE   
  11. static   char   THIS_FILE[]   =   __FILE__;   
  12. #endif   
  13.   
  14. /////////////////////////////////////////////////////////////////////////////   
  15. //   CMSGSocket   
  16.   
  17. CMSGSocket::CMSGSocket()   
  18. {   
  19. bForceNoLoopback   =   FALSE;   
  20. bDataReceived   =   false/*   Variable   defined   for   this   project.   Not   necessarily   part   of   CMsocket   */   
  21. number=0;   
  22. for(int   i=0;i <40;i++)   
  23. {   
  24. ready[i]=false;   
  25. }   
  26. number=0;   
  27. newfile=false;   
  28. receivenumber=0;   
  29. filename= " ";   
  30.   
  31.   
  32. }   
  33.   
  34. CMSGSocket::~CMSGSocket()   
  35. {   
  36. }   
  37.   
  38.   
  39. //   Do   not   edit   the   following   lines,   which   are   needed   by   ClassWizard.   
  40. #if   0   
  41. BEGIN_MESSAGE_MAP(CMSGSocket,   CSocket)   
  42. //{{AFX_MSG_MAP(CMSGSocket)   
  43. //}}AFX_MSG_MAP   
  44. END_MESSAGE_MAP()   
  45. #endif //   0   
  46.   
  47. /////////////////////////////////////////////////////////////////////////////   
  48. //   CMSGSocket   member   functions   
  49. BOOL   CMSGSocket::CreateSocket(LPCTSTR   strGroupIP,   UINT   nGroupPort)   
  50. {   
  51. /*   Create   socket   for   receiving   packets   from   multicast   group   */   
  52. LeaveGroup();   
  53. //if(!Create(nGroupPort,   SOCK_DGRAM,   FD_READ|FD_WRITE))     //CAsyncSocket   
  54. if(!Create(nGroupPort,   SOCK_DGRAM,   NULL))     //CSocket   
  55. {   
  56. AfxMessageBox( "建立连接时出错,检查该频道是否已被别的窗口占用! ");   
  57. return   FALSE;   
  58. }   
  59.   
  60. BOOL   bMultipleApps   =   TRUE; /*   allow   reuse   of   local   port   if   needed   */   
  61. SetSockOpt(SO_REUSEADDR,   (void*)&bMultipleApps,   sizeof(BOOL),   SOL_SOCKET);   
  62.   
  63. /*   Fill   m_saHostGroup_in   for   sending   datagrams   */   
  64. memset(&m_saHostGroup,   0,   sizeof(m_saHostGroup));   
  65. m_saHostGroup.sin_family   =   AF_INET;   
  66. m_saHostGroup.sin_addr.s_addr   =   inet_addr(strGroupIP);   
  67. m_saHostGroup.sin_port   =   htons((USHORT)nGroupPort);   
  68.   
  69. /*   Join   the   multicast   group   */   
  70. m_mrMReq.imr_multiaddr.s_addr   =   inet_addr(strGroupIP); /*   group   addr   */    
  71.  m_mrMReq.imr_interface.s_addr   =   htons(INADDR_ANY); /*   use   default   */     
  72. if(setsockopt(m_hSocket,   IPPROTO_IP,   IP_ADD_MEMBERSHIP,   (char   FAR   *)&m_mrMReq,   sizeof(m_mrMReq))   <   0)   
  73. {   
  74. AfxMessageBox( "CreateReceivingSocket   failed ");   
  75. return   FALSE;   
  76. }   
  77.   
  78. return   TRUE;   
  79. }   
  80.   
  81. void   CMSGSocket::OnReceive(int   nErrorCode)   
  82. {   
  83. ::SetActiveWindow(AfxGetApp()-> m_pMainWnd-> m_hWnd);   
  84. //AfxMessageBox( "MSG收到数据! ");   
  85. //return;   
  86. int   nError   =   ReceiveFrom   (&msg_commanddata,sizeof(csock_data),   m_strSendersIP,   m_nSendersPort);   
  87.   
  88. if(nError   ==   SOCKET_ERROR)   
  89. AfxMessageBox( "Error   receiving   data   from   the   host   group ");   
  90. else   
  91. {   
  92. if   (!bForceNoLoopback   ||   (bForceNoLoopback   &&   !(m_strSendersIP   ==   m_strLocalIP   &&   m_nSendersPort   ==   m_nLocalPort)))   
  93. {   
  94. //lyksetdata1(3);   
  95. //AfxMessageBox( "MSG收到数据! ");   
  96. ::PostMessage(GetActiveWindow(   ),WM_COMMAND,WM_RECEIVEMSG,(LPARAM)0);   
  97. }   
  98. }   
  99. CSocket::OnReceive(nErrorCode);     
  100. }   
  101.   
  102.   
  103. BOOL   CMSGSocket::LeaveGroup()   
  104. {   
  105. if(setsockopt   (m_hSocket,   IPPROTO_IP,   IP_DROP_MEMBERSHIP,   (char   FAR   *)&m_mrMReq,   sizeof(m_mrMReq))   <   0)   
  106. return   FALSE;   
  107.   
  108. Close(); //   Close   receving   socket   
  109. return   TRUE;   
  110. }   
  111.   
  112. /*  
  113. BOOL   CMSGSocket::Send(const   void*   strMessage,   int   nSize)  
  114.  
  115. //CString   str=strMessage;  
  116. //AfxMessageBox(str);  
  117.  
  118. if(SendTo(strMessage,   nSize,   (SOCKADDR*)&m_saHostGroup,   sizeof(SOCKADDR),   0)   ==   SOCKET_ERROR)  
  119. return   FALSE;  
  120. else  
  121. return   TRUE;  
  122.  
  123. */   
  124. BOOL   CMSGSocket::Send(csock_data   m_data1)   
  125. {   
  126.   
  127. if(SendTo(&m_data1,   sizeof(csock_data),   (SOCKADDR*)&m_saHostGroup,   sizeof(SOCKADDR),   0)   ==   SOCKET_ERROR)   
  128. {   
  129.         return   FALSE;   
  130. }   
  131. else   
  132. {   
  133. //AfxMessageBox( "MSGSend! ");   
  134. return   TRUE;   
  135. }   
  136. }   
  137.   
  138. BOOL   CMSGSocket::TextSend(CString   str)   
  139. {   
  140. CString   st=str;   
  141. st+= "/@&/ ";   
  142. //BOOL   bo=Send(st,   st.GetLength()+1);   
  143. return   0;   
  144. }   
  145.   
  146. BOOL   CMSGSocket::GetMaker(void)   
  147. {   
  148. return   bDataReceived;   
  149. }   
  150.   
  151. void   CMSGSocket::SetMaker(BOOL   da)   
  152. {   
  153. bDataReceived=da;   
  154. //ready[number]==da;   
  155. }   
  156.   
  157. void   CMSGSocket::Init(void)   
  158. {   
  159. bForceNoLoopback   =   FALSE;   
  160. bDataReceived   =   false/*   Variable   defined   for   this   project.   Not   necessarily   part   of   CMSGSocket   */   
  161. number=0;   
  162. for(int   i=0;i <40;i++)   
  163. {   
  164. ready[i]=false;   
  165. }   
  166. }   
  167.   
  168.   
  169. BOOL   CMSGSocket::SendFile(CString   filename)   
  170. {   
  171. return   0;   
  172. }   
  173.   
  174. void   CMSGSocket::ReadFile()   
  175. {   
  176.   
  177. }   
  178.   
  179. BOOL   CMSGSocket::SendData(SOCKET_STREAM_FILE_INFO   m_data1)   
  180. {   
  181. //AfxMessageBox( "send........ ");   
  182. if(SendTo(&m_data1,   sizeof(SOCKET_STREAM_FILE_INFO),   (SOCKADDR*)&m_saHostGroup,   sizeof(SOCKADDR),   0)   ==   SOCKET_ERROR)   
  183. {   
  184. //AfxMessageBox( "send   false ");   
  185.         return   FALSE;   
  186. }   
  187. else   
  188. {   
  189. //AfxMessageBox( "send   ok ");   
  190. return   TRUE;   
  191. }   
  192. }  


 

[cpp] view plaincopy
  1. #if   !defined(AFX_MSGSocket_H__257F140C_C139_4112_BACA_2C16C0F155B8__INCLUDED_)   
  2. #define   AFX_MSGSocket_H__257F140C_C139_4112_BACA_2C16C0F155B8__INCLUDED_   
  3.   
  4. #if   _MSC_VER   >   1000   
  5. #pragma   once   
  6. #endif   //   _MSC_VER   >   1000   
  7. //   MSGSocket.h   :   header   file   
  8. //   
  9.   
  10. /////////////////////////////////////////////////////////////////////////////   
  11. //   CMSGSocket   command   target   
  12.   
  13. class   CMSGSocket   :   public   CSocket   
  14. {   
  15. //   Attributes   
  16. public:   
  17. char   m_strBuffer[32768];   
  18. char   m_strBuffer1[32768];   
  19. char   m_strBuffer2[32768]; //   Receiving   buffer   for   the   packet   that   has   arrived   
  20. SOCKADDR_IN   m_saHostGroup; //   SOCKADDR   structure   to   hold   IP/Port   of   the   Host   group   to   send   data   to   it   
  21. ip_mreq   m_mrMReq; //   Contains   IP   and   interface   of   the   host   group   
  22. UINT   m_nSendersPort; //   Holds   Port   No.   of   the   socket   from   which   last   packet   was   received   
  23. CString   m_strSendersIP; //   Hold   IP   of   the   socket   from   which   the   last   packet   was   received   
  24. UINT   m_nLocalPort; //   Ephemeral   port   number   of   the   sending   port   
  25. CString   m_strLocalIP; //   IP   Address   of   the   local   host   or   your   machine   
  26. BOOL   bForceNoLoopback; //   If   interface   does   not   support   lopback   and   the   service   is   required,   the   bool   is   set   to   true   
  27.   
  28. BOOL   bDataReceived;   
  29. BOOL   LeaveGroup();   
  30. //BOOL   Send(const   void*,   int);   
  31. BOOL   Send(csock_data   m_data1);   
  32. BOOL   CreateSocket(LPCTSTR,   UINT);   
  33. BOOL   ready[40];   
  34. int   number;   
  35. CString   text;   
  36.   
  37. ////////////////   
  38. csock_data   msg_commanddata;   
  39.   
  40. BOOL   newfile;   
  41. DWORD   fileID;   
  42. DWORD     receivenumber;   
  43. CString   filename;   
  44.   
  45. BOOL   GetMaker(void);   
  46. void   SetMaker(BOOL   da);   
  47. void   ReadFrom(void);   
  48. void   Init(void);   
  49. BOOL   TextSend(CString   text);   
  50.   
  51. BOOL   SendFile(CString   filename);   
  52. void   ReadFile(void);   
  53. BOOL   SendData(SOCKET_STREAM_FILE_INFO   m_data1);   
  54.   
  55.   
  56. /////////////////////   
  57. ////////////////   
  58. HINSTANCE   glib;   
  59. LYKGETDATA   lykgetdata1;   
  60. LYKSETDATA   lyksetdata1;   
  61.   
  62.   
  63. //   Operations   
  64. public:   
  65. CMSGSocket();   
  66. virtual   ~CMSGSocket();   
  67.   
  68. //   Overrides   
  69. public:   
  70. //   ClassWizard   generated   virtual   function   overrides   
  71. //{{AFX_VIRTUAL(CMSGSocket)   
  72. public:   
  73. virtual   void   OnReceive(int   nErrorCode);   
  74. //}}AFX_VIRTUAL   
  75.   
  76. //   Generated   message   map   functions   
  77. //{{AFX_MSG(CMSGSocket)   
  78. //   NOTE   -   the   ClassWizard   will   add   and   remove   member   functions   here.   
  79. //}}AFX_MSG   
  80.   
  81. //   Implementation   
  82. protected:   
  83. };   
  84.   
  85. /////////////////////////////////////////////////////////////////////////////   
  86.   
  87. //{{AFX_INSERT_LOCATION}}   
  88. //   Microsoft   Visual   C++   will   insert   additional   declarations   immediately   before   the   previous   line.   
  89.   
  90. #endif   //   !defined(AFX_MSGSocket_H__257F140C_C139_4112_BACA_2C16C0F155B8__INCLUDED_)   
  91.   
  92.   
  93. 用法是:   
  94.   
  95. void   CMainFrame::SendMSG(int   pcommand,int   pmsg)   
  96. {   
  97. if(!MSG_Socket.CreateSocket( "234.5.6.7 ",   206))   
  98. AfxMessageBox( "建立网络连接出错! ");   
  99.   
  100. //AfxMessageBox( "SendMSG ");   
  101. //return;   
  102. //AfxMessageBox( "aa ");   
  103. ::memset(&msg_commanddata,0,sizeof(csock_data));   
  104. msg_commanddata.command=pcommand;   
  105. msg_commanddata.serial=pmsg;   
  106. POINT   pt;   
  107. GetCursorPos(&pt);   
  108. msg_commanddata.mousex=pt.x;   
  109. msg_commanddata.mousey=pt.y;   
  110. //////////////   
  111. char   ch[128];   
  112.         ::gethostname(ch,100);   
  113. hostent*   tent=::gethostbyname(ch);   
  114. msg_commanddata.IP[0][0]=(byte)tent-> h_addr[0];   
  115. msg_commanddata.IP[0][1]=(byte)tent-> h_addr[1];   
  116. msg_commanddata.IP[0][2]=(byte)tent-> h_addr[2];   
  117. msg_commanddata.IP[0][3]=(byte)tent-> h_addr[3];   
  118.   
  119. ///////////////////////////////////////////   
  120. if(!MSG_Socket.Send(msg_commanddata))   
  121. {   
  122. //   
  123. for(int   i=0;i <3;i++)   
  124. {   
  125. //Sleep(100);   
  126. if(!MSG_Socket.Send(msg_commanddata))   
  127. {   
  128. //AfxMessageBox( "send   data   failed ");   
  129.                         //return;   
  130. }   
  131. else   
  132. {   
  133.                                   //AfxMessageBox( "send   data   failed ");   
  134. }   
  135. }   
  136. }   
  137. else   
  138. {   
  139. }   
  140. //AfxMessageBox( "send   end ");   
  141. //return;   
  142. }   


 

 

[cpp] view plaincopy
  1. //发送端程序  
  2.   
  3.   
  4.   
  5. #include <stdio.h>  
  6. #include <winsock.h>  
  7.   
  8.   
  9.   
  10. int main(int argc, char* argv[])  
  11. {  
  12.     WSADATA wsaData;          //指向WinSocket信息结构的指针  
  13.     SOCKET sockListener;  
  14.     SOCKADDR_IN sin,saUdpServ;  
  15.     BOOL fBroadcast = TRUE;  
  16.     char sendBuff[1024];  
  17.     int nSize;  
  18.     int ncount=0;  
  19.  // 初始化winsock库,使用socket的前提  
  20.     if(WSAStartup(MAKEWORD( 1, 1 ), &wsaData )!=0)//进行WinSocket的初始化  
  21.     {  
  22.         printf("Can't initiates windows socket!Program stop.\n");//初始化失败返回-1  
  23.         return -1;  
  24.     }  
  25.  // 创建socket  
  26.     sockListener=socket(PF_INET,SOCK_DGRAM,0);  
  27.  // 打开广播选项,是socket可以广播消息  
  28.     setsockopt ( sockListener,SOL_SOCKET,SO_BROADCAST, (CHAR *)&fBroadcast,sizeof ( BOOL ));  
  29.  // 将socket绑定到本地端口  
  30.     sin.sin_family = AF_INET;  
  31.     sin.sin_port = htons(0);  
  32.     sin.sin_addr.s_addr = htonl(INADDR_ANY);  
  33.     if(bind( sockListener, (SOCKADDR *)&sin, sizeof(sin))!=0)  
  34.     {  
  35.         printf("Can't bind socket to local port!Program stop.\n");//初始化失败返回-1  
  36.         return -1;  
  37.     }  
  38.  // 设定广播的目的端口  
  39.     saUdpServ.sin_family = AF_INET;  
  40.     saUdpServ.sin_addr.s_addr = htonl ( INADDR_BROADCAST );  
  41.     saUdpServ.sin_port = htons (7001);//发送用的端口,可以根据需要更改  
  42.     nSize = sizeof ( SOCKADDR_IN );  
  43.     while(1)  
  44.     {  
  45.   // 广播消息  
  46.         sprintf(sendBuff,"Message %d",ncount++);  
  47.         sendto ( sockListener,sendBuff,  
  48.             lstrlen (sendBuff),  
  49.             0,  
  50.             (SOCKADDR *) &saUdpServ,  
  51.             sizeof ( SOCKADDR_IN ));  
  52.         printf("%s\n",sendBuff);  
  53.     }  
  54.  return 0;  
  55. }  
  56.   
  57.   
  58. //接收  
  59. #include <stdio.h>  
  60. #include <winsock.h>  
  61. #include <conio.h>  
  62.   
  63. int main(int argc, char* argv[])  
  64. {  
  65.     WSADATA wsaData;          //指向WinSocket信息结构的指针  
  66.     SOCKET sockListener;  
  67.     SOCKADDR_IN sin,saClient;  
  68.     char cRecvBuff[1024];  
  69.     int nSize,nbSize;  
  70.     int iAddrLen=sizeof(saClient);  
  71.     if(WSAStartup(MAKEWORD( 1, 1 ), &wsaData )!=0)//进行WinSocket的初始化  
  72.     {  
  73.         printf("Can't initiates windows socket!Program stop.\n");//初始化失败返回-1  
  74.         return -1;  
  75.     }  
  76.  // 绑定到7001端口,以监听来自网络的数据  
  77.     sockListener=socket(AF_INET, SOCK_DGRAM,0);  
  78.     sin.sin_family = AF_INET;  
  79.     sin.sin_port = htons(7001);//发送端使用的发送端口,可以根据需要更改  
  80.     sin.sin_addr.s_addr = htonl(INADDR_ANY);  
  81.     if(bind( sockListener, (SOCKADDR FAR *)&sin, sizeof(sin))!=0)  
  82.     {  
  83.         printf("Can't bind socket to local port!Program stop.\n");//初始化失败返回-1  
  84.         return -1;  
  85.     }  
  86.     while(1)  
  87.     {  
  88.         nSize = sizeof ( SOCKADDR_IN );  
  89.   // 接受消息  
  90.         if((nbSize=recvfrom (sockListener,cRecvBuff,1024,0,(SOCKADDR FAR *) &saClient,&nSize))==SOCKET_ERROR)  
  91.         {  
  92.             printf("Recive Error");  
  93.             break;  
  94.         }  
  95.         cRecvBuff[nbSize] = '\0';  
  96.         printf("%s\n",cRecvBuff);  
  97.     
  98.     
  99.     
  100.     }  
  101.     return 0;  
  102. }  

广播

广播是指在一个局域网中向所有的网上节点发送信息。这是UDP连接的一种

广播有一个广播组,即只有一个广播组内的节点才能收到发往这个广播组的信息。什么决定了一个广播组呢,就是端口号,局域网内一个节点,如果设置了广播属性并监听了端口号A后,那么他就加入了A组广播,这个局域网内所有发往广播端口A的信息他都收的到。在广播的实现中,如果一个节点想接受A组广播信息,那么就要先将他绑定给地址和端口A,然后设置这个socket的属性为广播属性。如果一个节点不想接受广播信息,而只想发送广播信息,那么不用绑定端口,只需要先为socket设置广播属性后,向广播地址INADDR_BROADCAST的A端口发送udp信息即可。详细的程序实现如下:

1.初始化

    WSAStartup(MAKEWORD(2,2),&wsad);

2.创建一个UDP的socket 
    s=socket(AF_INET,SOCK_DGRAM,0);

3.如果这个socket希望收到信息,则需要绑定地址和这组广播的端口号,如果只是希望发送广播信息,则不需要这步

    SOCKADDR_IN udpAdress,sender; 
    int senferAddSize=sizeof(sender); 
    udpAdress.sin_family=AF_INET; 
    udpAdress.sin_port=htons(11114); 
    udpAdress.sin_addr.s_addr=inet_addr("10.11.131.32"); 
    bind(s,(SOCKADDR*)&udpAdress,sizeof(udpAdress));

//这样这个节点即可收到局域网内所有发往端口11114的广播信息

4.设置socket的属性为广播 
    bool optval=true; 
    setsockopt(s,SOL_SOCKET,SO_BROADCAST,(char*)&optval,sizeof(bool));

5.下面就可以使用recvfrom或sendto来收发广播信息了

这里是接受,这是一个阻塞操作 
            ret=recvfrom(s,data,1000,0,(SOCKADDR*)&sender,&senferAddSize);

这里是像该广播组发送信息,注意发送的地址为广播地址INADDR_BROADCAST,端口号为改组广播的端口号11114

    SOCKADDR_IN dstAdd; 
    dstAdd.sin_family=AF_INET; 
    dstAdd.sin_port=htons(11114); 
    dstAdd.sin_addr.s_addr=INADDR_BROADCAST; 
    sendto(s,data(),totalbyte,0,(SOCKADDR*)&dstAdd,sizeof(SOCKADDR));

多播

多播与广播不同,多播是指一条信息向局域网内有限几个节点传递,而广播是不管某个节点是否在制定组内,都会向这个节点发送广播信息,容易造成网络负担严重。

多播的实现是靠多播组,在局域网内,一个多播地址唯一的定义了一个多播组(端口号任意),可以使用的多播地址是有规定的,从224.0.0.0—239.255.255.255之间,但是其中的一些地址不能用,是用作特殊用途的:224.0.0.0 –224.0.0.2  224.0.1.1  224.0.0.9 224.0.1.24。一个节点如果想接受自某个多播组或向某个多播组发送信息,必须首先加入多播组,然后给予UDP发送。下面是详细的代码实现。

1.初始化

    WSAStartup(MAKEWORD(2,2),&wsad);

2.这里传建一个用于多播通信的socket,注意这个socket的参数为设置成多播 
    s=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,WSA_FLAG_MULTIPOINT_C_LEAF|WSA_FLAG_MULTIPOINT_D_LEAF|WSA_FLAG_OVERLAPPED);

3.将socket绑定到一个本地地址、端口,和广播不同,在多播中,无论是发送还是接收端都必须绑定一个本地地址,这个地址就是多播通信时处理信息的端口
    udpAdress.sin_family=AF_INET; 
    udpAdress.sin_port=htons(22222); 
    udpAdress.sin_addr.s_addr=inet_addr("10.11.131.32"); 
    bind(s,(SOCKADDR*)&udpAdress,sizeof(udpAdress));

4.定义多播组的地址 
    multiCastGroup.sin_family=AF_INET; 
    multiCastGroup.sin_port=htons(1111);此处端口任意,每个节点的可以设置成不同的 
    multiCastGroup.sin_addr.s_addr=inet_addr("224.0.0.3"); 此处需使用上面规定地址段内的多播地址

5.加入这个多播组。注意这里的函数返回了一个socket,这个socket不负责通信,只是在脱离多播组时使用

    SOCKET sockM=WSAJoinLeaf(s,(SOCKADDR*)&multiCastGroup,sizeof(multiCastGroup),NULL,NULL,NULL,NULL,JL_BOTH);

6.下面使用recvfrom接受多播信息,或者使用sendto发送多播信息  

ret=recvfrom(s,data,1000,0,(SOCKADDR*)&sender,&senferAddSize);

sendto(s,data(),totalbyte,0,(SOCKADDR*)&multiCastGroup,sizeof(multiCastGroup));

7.最后关闭清理 
    closesocket(sockM); 
    closesocket(s); 
    WSACleanup();

其他:

1)在多播组中,默认情况下一个发出多播信息的节点也会收到自己发送的信息,这称为多播回环,可以关闭多播回环:

bool val=false;

setsocket(s,IPPROTO_IP,IP_MULTICAST_LOOP,(char*)val,sizeof(val));

2)在多播时,通常要设置适当的TTL(TTL的值是多少,那么多播信息就可以经过多少路由器,每经过一个路由器,TTl的值自动减1):

int val=3;

setsocket(s,IPPROTO_IP,IP_MULTICAST_TTL,(char*)val,sizeof(int));

 

[cpp] view plaincopy
  1.     //////////////////////////////////////////////////////////////////////////  
  2.     // UDPServer.cpp   
  3. #include <stdio.h>  
  4. #include <WINSOCK2.H>   
  5. #pragma comment(lib,"WS2_32.lib")  
  6. #define BUF_SIZE    64   
  7.     int main(void)  
  8.     {      
  9.         WSADATA wsd;      
  10.         SOCKET  s;      
  11.         int     nRet;       
  12.         // 初始化套接字动态库      
  13.         if(WSAStartup(MAKEWORD(2,2),&wsd) != 0)      
  14.         {          
  15.             printf("WSAStartup failed !\n");          
  16.             return 1;      
  17.         }       
  18.         // 创建套接字      
  19.         s = socket(AF_INET,SOCK_DGRAM,0);      
  20.         if(s == INVALID_SOCKET)      
  21.         {          
  22.             printf("socket() failed ,Error Code:%d\n",WSAGetLastError());          
  23.             WSACleanup();          
  24.             return 1;      
  25.         }       
  26.         SOCKET      socketSrv = socket(AF_INET,SOCK_DGRAM,0);      
  27.         SOCKADDR_IN addrSrv;      
  28.         SOCKADDR_IN addrClient;      
  29.         char        buf[BUF_SIZE];      
  30.         int         len = sizeof(SOCKADDR);       
  31.         // 设置服务器地址      
  32.         ZeroMemory(buf,BUF_SIZE);      
  33.         addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);      
  34.         addrSrv.sin_family = AF_INET;      
  35.         addrSrv.sin_port = htons(5000);       
  36.         // 绑定套接字      
  37.         nRet = bind(socketSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));      
  38.         if(SOCKET_ERROR == nRet)         
  39.         {             
  40.             printf("bind failed !\n");             
  41.             closesocket(s);             
  42.             WSACleanup();             
  43.             return -1;         
  44.         }      
  45.         // 从客户端接收数据      
  46.         nRet = recvfrom(socketSrv,buf,BUF_SIZE,0,(SOCKADDR*)&addrClient,&len);      
  47.         if(SOCKET_ERROR == nRet)         
  48.         {             
  49.             printf("recvfrom failed !\n");             
  50.             closesocket(s);             
  51.             WSACleanup();             
  52.             return -1;         
  53.         }      
  54.         // 打印来自客户端发送来的数据      
  55.         printf("Recv From Client:%s\n",buf);       
  56.         // 向客户端发送数据      
  57.         sendto(socketSrv,"UDP Hello World !",sizeof("UDP Hello World !"),0,(SOCKADDR*)&addrClient,len);      
  58.         closesocket(s);      
  59.         WSACleanup();      
  60.         return 0;  
  61.     }  


 

[cpp] view plaincopy
  1.     //////////////////////////////////////////////////////////////////////////  
  2.     // UDPClient.cpp   
  3. #include <stdio.h>  
  4. #include <WINSOCK2.H>   
  5. #pragma comment(lib,"WS2_32.lib")  
  6. #define BUF_SIZE    64   
  7.     int main(void)  
  8.     {      
  9.         WSADATA wsd;          
  10.         SOCKET  s;       
  11.         // 初始化套接字动态库      
  12.         if(WSAStartup(MAKEWORD(2,2),&wsd) != 0)      
  13.         {          
  14.             printf("WSAStartup failed !\n");          
  15.             return 1;      
  16.         }       
  17.         // 创建套接字      
  18.         s = socket(AF_INET,SOCK_DGRAM,0);      
  19.         if(s == INVALID_SOCKET)      
  20.         {          
  21.             printf("socket() failed, Error Code:%d\n",WSAGetLastError());          
  22.             WSACleanup();          
  23.             return 1;      
  24.         }       
  25.         char        buf[BUF_SIZE];    
  26.         // 接受数据      
  27.         SOCKADDR_IN servAddr;         
  28.         // 服务器套接字地址      
  29.         SOCKET      sockClient = socket(AF_INET,SOCK_DGRAM,0);      
  30.         int         nRet;     ZeroMemory(buf,BUF_SIZE);      
  31.         strcpy(buf,"UDP Hello World !");       
  32.         // 设置服务器地址      
  33.         servAddr.sin_family = AF_INET;      
  34.         servAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.254");      
  35.         servAddr.sin_port = htons(5000);       
  36.         // 向服务器发送数据      
  37.         int nServAddLen = sizeof(servAddr);      
  38.         if(sendto(sockClient,buf,BUF_SIZE,0,(sockaddr *)&servAddr,nServAddLen) == SOCKET_ERROR)      
  39.         {          
  40.             printf("recvfrom() failed:%d\n",WSAGetLastError());          
  41.             closesocket(s);          
  42.             WSACleanup();          
  43.             return 1;      
  44.         }      
  45.         nRet = recvfrom(sockClient,buf,BUF_SIZE,0,(sockaddr *)&servAddr,&nServAddLen);      
  46.         if(SOCKET_ERROR == nRet)         
  47.         {             
  48.             printf("recvfrom failed !\n");             
  49.             closesocket(s);             
  50.             WSACleanup();             
  51.             return -1;         
  52.         }       
  53.         // 打印来自服务端发送来的数据      
  54.         printf("Recv From Server:%s\n",buf);      
  55.         closesocket(s);      
  56.         WSACleanup();      
  57.         return 0;  
  58.     }  


 

 本文讲述了SOCKADDR 与 SOCKADDR_IN 的区别与联系。已经里面涉及的结构体 联合体 等的一些细节问题。这个是一个很基础的问题,但是很多人都是似是而非的理解着!下面详解了这个谜团!

-----------------------------------------------------------------------------------------------------------------------

struct sockaddr {
        unsigned short sa_family; //    地址族, AF_xxx               AF_INET 不涉及转序的问题
        char sa_data[14];    // 14字节的协议地址 网络字节顺序的
    };
   
上面是通用的socket地址,共16个字节!

具体到Internet socket,用下面的结构,二者可以进行类型转换
   
struct sockaddr_in {
        short int sin_family; /* 地址族 */
        unsigned short int sin_port; /* 端口号 */
       struct in_addr sin_addr; /* Internet地址 */
        unsigned char sin_zero[8]; /* 与struct sockaddr一样的长度 */ 16个字节
    };
   
    ---------------------------struct in_addr 就是32位IP地址---------------------------------
第一种表示方式:   
    struct in_addr {
        unsigned long s_addr;
    };

第二种表示方式:
struct in_addr
{  
   union 
{    
     struct { u_char s_b1,s_b2,s_b3,s_b4;} S_un_b;    
     struct { u_short s_w1,s_w2;} S_un_w;    
     u_long S_addr; 
} S_un;
};

利用u_long htonl(u_long hostlong);将主机字节序转换为TCP/IP网络字节序.
利用u_short htons(u_short hostshort);将主机字节序转换为TCP/IP网络字节序.

inet_addr()是将一个点分制的IP地址(如192.168.0.1)转换为上述结构中需要的32位IP地址(0xC0A80001)。

通常的用法是:
SOCKET sockfd;
struct sockaddr_in my_addr;   //SOCKETADDR_IN my_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0); /* 做一些错误检查! */

my_addr.sin_family = AF_INET; /* 主机字节序 */
my_addr.sin_port = htons(MYPORT); /* short, 网络字节序 */

//有两种方式 对应上面 in_addr 的两种方式
my_addr.sin_addr.s_addr = inet_addr("192.168.0.1");
//my_addr.sin_addr.S_un.s_addr = inet_addr("192.168.0.1");

bzero(&(my_addr.sin_zero), 8); /* zero the rest of the struct */
/* 不要忘了为bind()做错误检查: */
bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));


转自http://blog.csdn.net/jiangxinyu/article/details/7586513

原创粉丝点击