|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionThis articles shows how to retrieve a list of PCs on the local network which are running MS SQL Server, and gets information about the instances, such as server name, instance name, version, and databases. BackgroundTo get a list of the nearby SQL Servers is as simple as typing "osql /L" on a command prompt. But getting them programmatically, for use inside an application, is a bit trickier. The most common use for this would be to create a connection string building form in managed code, which will be the subject of my next article. Note also, that while the subject matter is SQL Server, the first half of this article deals mostly with sockets. To create a list of SQL Server instances, I first tried several different methods, all of which had two things in common: they took a very long time, and they were only marginally successful at finding SQL Servers instances on the network. Eventually, I had the idea of running "osql -L" with a packet sniffer running (I used Ethereal), to see how osql was doing it. Its method was to send out a Broadcast UDP packet on port 1434, with the contents of just a byte of 0x02, to which each server would respond. Sending such a message is quite simple: Socket socket = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp );
// For .Net v 1.1 the options are cumbersome & hidden.
socket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.Broadcast, 1);
socket.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout, 3000);
// For .Net v 2.0 it's a bit simpler
// socket.EnableBroadcast = true; // for .Net v2.0
// socket.ReceiveTimeout = 3000; // for .Net v2.0
IPEndPoint ep = new IPEndPoint(IPAddress.Broadcast, 1434);
byte[] msg = new byte[] { 0x02 };
socket.SendTo(msg, ep);
It's vitally important that you set the timeout. Without it, the As it turns out, with the proper options set, getting a response is as simple as you'd hope. byte[] bytBuffer = new byte[256];
socket.Receive(bytBuffer);
The After we've received, processed and stored the response, we just keep looping until we don't get a response within the timeout. The downside of using a timeout, is that when it is reached, the I initially set the timeout to 3 seconds. The problem here was that after each response, I'd call Now, back to interpreting the response we've gotten, which is quite simple. The first three bytes are a byte of 0x05, followed by two bytes giving the length of the rest which is straight ASCII text of pairs of items, separated by semicolons: data item 1 name ; data item 1 value ; data item 2 name ; data item 2 value;
or more specifically: ServerName;DATA001;InstanceName;MSSQLSERVER;IsClustered;No;Version;8.00.194;tcp;1433
To make use of this, we'll have to convert from a byte array of ASCII characters to a .NET string of UNICODE characters, which the framework is nice enough to provide a method for (although it does bury in under Of course, while the information provided in the broadcast response is useful, it doesn't provide one vitally important piece of data: the list of databases on that server. To get that, we need to use more traditional database access methods. But, to do that, we are going to have to connect to the server, which means a connection string, which means a username & password. Once we've established a connection, getting the list of catalogs is a method built right into the DataTable schemaTable =
myConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Catalogs, null);
Using the codeEverything is packaged in the class SqlServerInfo[] servers = SqlServerInfo.Seek();
Each
Note that, although Next there are four Read/Write properties, which must be set to get any more information out of this class:
These establish how we are going to attempt to connect to that server. The final property retrieves a list of databases available on the server.
The first time it is called, it will attempt to connect to the server, so the above property needs to be set right. Finally, there are two methods:
SqlServerInfo Data = servers[0];
Console.WriteLine(Data.ToString());
Console.WriteLine("Version:", Data.Version);
Data.IntegratedSecurity = true;
foreach(string Catalog in Data.Catalogs)
{
Console.WriteLine(" {0}", Catalog);
}
History
| ||||||||||||||||||||