2012-05-10 30 views
2

我想枚举使用SQLBrowseConnect的本地SQL实例。一般来说,这工作正常,但我们有一个设置,导致SQLExpress实例未被发现。以下是有问题的代码:SQLBrowseConnect似乎没有枚举本地域上的服务器

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显示丢失的实例没有任何问题。

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

回答

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??? 
} 
+0

我想前三个字节是响应标头。 第一个字节显然是一些状态码,对我来说它总是0x05。 剩余的两个字节是响应长度。 – Shuric

相关问题