2

我正在尝试使用 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 显示丢失的实例没有任何问题。

我错过了什么真的很傻吗?请记住,在其他系统和设置上没有问题。

4

1 回答 1

2

经过大量调查,我无法真正找出问题所在。这台机器不会使用 SQLBrowseConnect 发现它自己的 SQL 实例。因此,我决定编写自己的版本。发现 SQL 实例非常容易。您只需将广播 UDP 数据包发送到端口 1434,其中包含有效负载 0x02(1 个字节)并等待 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???
}
于 2012-05-11T13:50:29.933 回答