2

I've inherited a Windows Service + Client application written in C#. The Windows Service opens a TCP/IP socket for listening as follows:

socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPHostEntry iphe = Dns.Resolve(Dns.GetHostName());
socket.Bind(new IPEndPoint(iphe.AddressList[0], ExportServiceRequest.DefaultPort));
socket.Listen(2);
// Wait for incoming connections and Accept them.

while the client connects as follows:

using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
    IPHostEntry iphe = Dns.Resolve(Dns.GetHostName());
    IPEndPoint ep = new IPEndPoint(iphe.AddressList[0], ExportServiceRequest.DefaultPort);
    socket.Connect(ep);
    // Talk to the server
}

The problem is that on certain machines with multiple network adapters, the 'wrong' adapter is picked by Dns.Resolve(), and the client connection fails.

I am aware that this code is aged and reeking, and haven't coded much raw socket code. Is there a best way to implement a Windows Service listening on a socket, such that at least local connections (from within the same machine) always succeed, regardless of how many network adapters the machine has?

Edit: my question appears poorly formulated. At the end of the day, I want the Windows Service to be accessible by a client, which always is running on the same machine, with no need for configuration. To anthropomorphize, I want the Windows Client to just yell at the server, "what IP address can I talk to you, oh Service running on TCP port ExportServiceRequest.DefaultPort on $LOCALHOST$? I want to talk to you", and have the ensuing TCP/IP conversation just work.

John Källén
  • 7,551
  • 31
  • 64
  • 1
    Title sounds like the start of a really poor programmers joke xD – RhysW May 09 '12 at 13:13
  • Assuming that the service is running on a single machine, and the `Dns.Resolve()` issue you refer to happens on the client, then the issue appears to be with your DNS settings. That said why is the client code not just using something like `IPHostEntry iphe = Dns.Resolve(SERVER_NAME);`? – Joshua Drake May 09 '12 at 13:13
  • er he has? the whole dns.gethostname() im guessing is the part which youve written as SERVER_NAME – RhysW May 09 '12 at 13:15
  • @RhysW: exactly; I don't want to burden the user of the client program with having to configure this. I want the client to have a reliable way to talk to the server. Do I really have to bind to *all* the interfaces in the Server to do this? – John Källén May 09 '12 at 13:18
  • http://stackoverflow.com/questions/515436/how-to-get-internet-ip/515449 could be of use to you @JohnKallen – RhysW May 09 '12 at 13:20
  • Dns.GetHostName `Gets the host name of the local computer.` so how exactly do you expect it to find the server? – Joshua Drake May 09 '12 at 13:21
  • @JoshuaDrake: The client will *always* be running on the local computer. – John Källén May 09 '12 at 13:22
  • I guess I do not understand the question then. I've +1'd it so that hopefully someone else can pitch in. – Joshua Drake May 09 '12 at 13:23
  • i think @Josh is saying that the host name is different to the server name, even when its on the same computer, which could be where your problem is stemming from, as youre hitting the right computer when there is one adapter, but when there is more than one its got no idea what the frig youre on about – RhysW May 09 '12 at 13:23
  • @RhysW that is effectively my point. If you have a single server MY_APPSERVER and several clients, they all need to talk to MY_APPSERVER, but if you are only supplying them with their own hostnames, they'll never be able to locate the server. – Joshua Drake May 09 '12 at 13:26
  • Interesting, the distinction between host name and server name is news to me. Where could I find documentation for this? I have been operating under the assumption that the host name and the server name are the same thing. In this particular scenario, however, the machine I want to talk to is the local host, and that's what I thought Dns.GetHostName() did. – John Källén May 09 '12 at 13:34
  • John i guess youve been very lucky up to this point XD think of it this way computer can host more than one server, if you give it a host name its basically saying hey code im thinking of a number in the 20's tell me which one, then its got all 10 choices to make from, and as c# wont make assumptions for you itll get to a fork in the road and take neither, gethostname does what it says on the tin, get me the name of the host of this server – RhysW May 09 '12 at 13:36
  • I understand that a machine can host more than one server, but aren't those servers distingished by their TCP ports (in the case of TCP services)? That is, I can talk to a service on a machine provided I have its name (host name) which can resolve to an IP address, and a TCP port. – John Källén May 09 '12 at 13:40

1 Answers1

1

Socket.Bind:

Before calling Bind, you must first create the local IPEndPoint from which you intend to communicate data. If you do not care which local address is assigned, you can create an IPEndPoint using IPAddress.Any as the address parameter, and the underlying service provider will assign the most appropriate network address. This might help simplify your application if you have multiple network interfaces.

(emphasis added). So that would be one suggested change.

I'd also suggest switching your Connect call to Connect(string,int):

Establishes a connection to a remote host. The host is specified by a host name and a port number.

(a host value of 'localhost' should be sufficient there)

That is, get rid of all of this mucking about with DNS, etc, and just rely on the underlying infrastructure to resolve these issues.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448