SQLBrowseConnect似乎不枚举本地域上的服务器

时间:2012-05-10 13:26:30

标签: c++ sql-server active-directory

我正在尝试使用SQLBrowseConnect枚举本地SQL实例。一般来说,这工作正常,但我们有一个设置导致SQLExpress实例未被发现。以下是有问题的代码:

SQLSetConnectAttr(hSQLHdbc, 
                  SQL_COPT_SS_BROWSE_SERVER,
                  _T("(local)"), 
                  SQL_NTS);

CString inputParam = _T("Driver={SQL Server}");
SQLBrowseConnect(hSQLHdbc, 
                 inputParam, 
                 SQL_NTS, 
                 szConnStrOut, 
                 MAX_RET_LENGTH, 
                 &sConnStrOut);

在失败的实例中,代码在域控制器上运行。缺少的SQL本地实例是SQLExpress实例(版本9)。然而,令人费解的是,运行sqlcmd -L会显示缺少的实例而没有任何问题。

我错过了一些非常愚蠢的东西吗?请记住,在其他系统和设置上没有问题。

1 个答案:

答案 0 :(得分:2)

经过多次调查,我无法真正找出具体问题。这台机器不会使用SQLBrowseConnect发现自己的SQL实例。因此我决定写自己的版本。发现SQL实例非常简单。您只需将广播UDP数据包发送到包含有效负载0x02(1字节)的端口1434,并等待SQL服务器响应。它们每个服务器响应一个数据包,详细说明该计算机上的所有实例。执行此操作所需的代码如下所示:

// to enumerate sql instances we simple send 0x02 as a broadcast to port 1434.
// Any SQL servers will then respond with a packet containing all the information
// about installed instances. In this case we only send to the loopback address

// initialise
WSADATA WsaData;
WSAStartup( MAKEWORD(2,2), &WsaData );

SOCKET udpSocket;
struct sockaddr_in serverAddress;       

if ((udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) 
{   
    return;
}

// set up the address
serverAddress.sin_family = AF_INET; 
serverAddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
serverAddress.sin_port = htons(1434);

// the payload
char payload = 0x02;  

// config the port for broadcast (not totally necessary right now but maybe in the future)
BOOL broadcast = TRUE;
setsockopt(udpSocket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<const char*>(&broadcast), sizeof(BOOL));

// receive address info
sockaddr_in RecvAddr;
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);

sockaddr_in SenderAddr;
int SenderAddrSize = sizeof (SenderAddr);

// bind the socket to the receive address info
int iResult = bind(udpSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
if (iResult != 0) 
{
    int a = WSAGetLastError();
    return;
}

if (sendto(udpSocket, &payload, 1, 0, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) 
{
    int a = WSAGetLastError();
    return;
}

// set up a select so that if we don't get a timely response we just bomb out.
fd_set fds ;
int n ;
struct timeval tv ;

// Set up the file descriptor set.
FD_ZERO(&fds) ;
FD_SET(udpSocket, &fds) ;

// Set up the struct timeval for the timeout.
tv.tv_sec = 5 ;
tv.tv_usec = 0 ;

// Wait until timeout or data received.
n = select ( (int)udpSocket, &fds, NULL, NULL, &tv ) ;
if ( n == 0)
{ 
    // timeout
    return;
}
else if( n == -1 )
{
    // error
    return;   
}

// receive buffer
char RecvBuf[1024];
int BufLen = 1024;
memset(RecvBuf, 0, BufLen);

iResult = recvfrom(udpSocket,
                   RecvBuf, 
                   BufLen, 
                   0, 
                   (SOCKADDR *) & SenderAddr, 
                   &SenderAddrSize);

if (iResult == SOCKET_ERROR) 
{
    int a = WSAGetLastError();
    return;        
}

// we have received some data. However we need to parse it to get the info we require
if (iResult > 0)
{
    // parse the string as required here. However, note that in my tests, I noticed
    // that the first 3 bytes always seem to be junk values and will mess with string
    // manipulation functions if not removed. Perhaps this is why SQLBrowseConnect
    // was having problems for me???
}