2012-05-10 58 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

相關問題