支持组通信的socket包装

Risun 2004-06-18

这几天在看IP组播,WinSock2虽然支持组播,但是没有提供独立的socket,编程非常不便,花了半下午的时间,学习了winsock2支持组播的部分api,包装了一个MulticastSocket类,可直接用于组播,尚未在多台及机器上测试。
源码如下:


MulticastSocket.h:
//=================================================================
/* MulticastSocket.h
 * MulticastSocket: send and receive data gram to and from a group
 * though the same port
 * Risun
 * yzy9508@hotmail.com
 * 2004-06-18
 */
//=================================================================
#ifndef MULTICASTSOCKET_H_
#define MULTICASTSOCKET_H_

#include <winsock2.h>

class MulticastSocket
{
private:
 SOCKADDR_IN my_addr;
 SOCKADDR_IN group_addr;
 SOCKET socket;

public:
 int create( int port );

 int close();

 int joinGroup( char group[] );

 int send( const char *out_buf, const int &buf_len, int *send_len);

 int receive( char *in_buf, const int &buf_len, int *rec_len );
};


#endif //MULTICASTSOCKET_H_


MulticastSocket.cpp

#include "MulticastSocket.h"
#include <stdio.h>

#define traceWSAErr(fun_name) printf ("in function: %s , Err: %d\n", fun_name, WSAGetLastError())


int MulticastSocket::create( int port )
{
 int ret;
 DWORD cbRet;
 
 socket = WSASocket(AF_INET, SOCK_DGRAM,  IPPROTO_UDP,

  (LPWSAPROTOCOL_INFO)NULL, 0, WSA_FLAG_OVERLAPPED

  | WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF);

 if ( socket == INVALID_SOCKET ) {

  traceWSAErr("MulticastSocket::create");
  return SOCKET_ERROR;
 }
 
 // 设置套接字为可重用端口地址
 bool bFlag = TRUE;

 ret = setsockopt(socket,         /* socket */
 
  SOL_SOCKET,               /* socket level */

  SO_REUSEADDR,         /* socket option */

  (char *)&bFlag,            /* option value */

  sizeof (bFlag));              /* size of value */


 if ( ret == SOCKET_ERROR )
 {
  traceWSAErr("MulticastSocket::create");
  return ret;
 }

 // 将套接字绑扎到用户指定端口及默认的接口
 my_addr.sin_family = PF_INET;

 my_addr.sin_port = htons( port );

 my_addr.sin_addr.s_addr = INADDR_ANY;

 ret = bind( socket, (struct sockaddr FAR *)&my_addr, sizeof(struct sockaddr) );


 if ( ret == SOCKET_ERROR )
 {
  traceWSAErr("MulticastSocket::create");
  return ret;
 }

 // 设置多址广播数据报传播范围(TTL)

 int nIP_TTL = 1;      // 在本子网中传播。如果要跨路由器,则路由器必须支持IGMP协议

 ret = WSAIoctl ( socket,              /* socket */

  SIO_MULTICAST_SCOPE, /* IP Time-To-Live */

  &nIP_TTL,                             /* input */

  sizeof (nIP_TTL),             /* size */

  NULL,                               /* output */

  0,                                  /* size */

  &cbRet,                             /* bytes returned */

  NULL,                                /* overlapped */

  NULL );                              /* completion routine */

 if ( ret == SOCKET_ERROR )
 {
  traceWSAErr("MulticastSocket::create");
  return ret;
 }


 // 允许内部回送(LOOPBACK)。Windows 95不支持改选项

 bFlag = TRUE;

 ret = WSAIoctl ( socket,                        /* socket */

  SIO_MULTIPOINT_LOOPBACK,         /* LoopBack on or off */

  &bFlag,                                               /* input */

  sizeof (bFlag),                    /* size */

  NULL,                                      /* output */

  0,                                         /* size */

  &cbRet,                                    /* bytes returned */

  NULL,                                      /* overlapped */

  NULL);                                     /* completion routine */

 if ( ret == SOCKET_ERROR )
 {
  traceWSAErr("MulticastSocket::create");
  return ret;
 }

 return 0;
}

int MulticastSocket::close()
{
 if ( socket == INVALID_SOCKET )
  closesocket( socket );

 return 0;
}

int MulticastSocket::joinGroup( char group[] )
{
 int ret = 0;
 int len;

 len = sizeof( group_addr );

 ret = WSAStringToAddress ( group,          /* address string */
  AF_INET,                                              /* address family */
  NULL,                                                 /* protocol info structure */
  (LPSOCKADDR)&group_addr,                   /* socket address string */
  &len);                                              /* length of socket structure */
 group_addr.sin_port = my_addr.sin_port;

 if ( ret == SOCKET_ERROR )
 {
  traceWSAErr("MulticastSocket::joinGroup");
  return ret;
 }


 // 加入到指定多址广播组,指定为既作发送者又作接收者

 // 在IP multicast中,返回的套接字描述符和输入的套接字描述符相同。
 SOCKET new_socket;

 new_socket = WSAJoinLeaf ( socket, /* socket */

  (PSOCKADDR)&group_addr, /* multicast address */

  sizeof (group_addr),             /* length of addr struct */      

  NULL,                   /* caller data buffer */

  NULL,                   /* callee data buffer */

  NULL,                   /* socket QOS setting */

  NULL,                   /* socket group QOS */

  JL_BOTH);               /* do both: send *and* receive */

 if ( new_socket == INVALID_SOCKET )
 {
  traceWSAErr("MulticastSocket::joinGroup");
  return ret;
 }

 //closesocket( new_socket );

 return ret;
}

int MulticastSocket::send( const char *out_buf, const int &buf_len, int *send_len )
{
 int ret = 0;
 DWORD cb_ret;
 WSABUF wsa_buf;

 wsa_buf.len = buf_len;
 wsa_buf.buf = const_cast<char *>( out_buf );

 ret = WSASendTo ( socket,           /* socket */

  &wsa_buf,                        /* output buffer structure */

  1,                                /* buffer count */

  &cb_ret,                           /* number of bytes sent */

  0,                                             /* flags */

  (struct sockaddr*)&group_addr,         /* destination address */

  sizeof(struct sockaddr),                   /* size of addr structure */

  NULL,                          /* overlapped structure */

  NULL);                            /* overlapped callback function */

 if ( ret == SOCKET_ERROR )
 {
  traceWSAErr("MulticastSocket::send");
  return ret;
 }

 *send_len = cb_ret;

 return 0;
}

int MulticastSocket::receive( char *in_buf, const int &buf_len, int *dat_len )
{
 int ret = 0;
 DWORD cb_ret, dFlag;
 WSABUF wsa_buf;

 wsa_buf.len = buf_len;
 wsa_buf.buf = in_buf;
 dFlag = 0;

 int addr_len = sizeof(my_addr);

 ret = WSARecvFrom ( socket,      /* socket */

  &wsa_buf,                        /* input buffer structure */

  1,                                /* buffer count */

  &cb_ret,                           /* number of bytes recv'd */

  &dFlag,                          /* flags */

  (struct sockaddr *)& my_addr,    /* source address */

  &addr_len,                            /* size of addr structure */

  NULL,                             /* overlapped structure */

  NULL);                            /* overlapped callback function */

 if ( ret == SOCKET_ERROR )
 {
  traceWSAErr("MulticastSocket::receive");
  return ret;
 }

 * dat_len = cb_ret;

 return 0;
}

posted on 2004-06-18 16:48  哲学 艺术 程序 人生  阅读(710)  评论(0编辑  收藏  举报

导航