Jump to content
Sign in to follow this  
Periander

.NET Sockets

Recommended Posts

I'm a bit rusty on networking, but I'm trying to implement a basic socket listener service.

 

It seems to me like I need to allocate a listener for every IP address that a PC exposes, is that the case? For example, 0.0.0.0 gives "Only one usage of each socket address (protocol/network address/port) is normally permitted".

 

Also, I can't get any IPv4 address to work without an exception, even though I'm running as administrator. 127.0.0.1 gives "An attempt was made to access a socket in a way forbidden by its access permissions".

 

IPv6 ::1 works a treat though.

 

I wrote up a simple test app for debugging, (don't worry that it's not async, and that I'm not 'using' and 'finally'ing please, it's just a test app):

 

using System;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace SimpleSocketListener
{
	class Program
	{
		static void Main(string[] args)
		{
			try
			{
				string hostName = Dns.GetHostName();
				hostName = "localhost";
				Console.WriteLine("Hostname: " + hostName);
				IPHostEntry iPHostEntry = Dns.GetHostEntry(hostName);
				IPAddress[] iPAddresses = iPHostEntry.AddressList;
				IPAddress iPAddress = iPAddresses[0];
				Console.WriteLine("Enter IP: ");
				string enteredIP = Console.ReadLine();
				try
				{
					iPAddress = IPAddress.Parse(enteredIP);
				}
				catch
				{
				}
				Console.WriteLine("IP Address: " + iPAddress.ToString());
				int port = 22222;
				Console.WriteLine("Port: " + port.ToString());
				TcpListener listener = new TcpListener(iPAddress, port);
				listener.Start();
				Socket socket = listener.AcceptSocket();
				Stream stream = new NetworkStream(socket);
				StreamReader steamReader = new StreamReader(stream);
				int read = 0;
				Console.WriteLine("--START--");
				while (!steamReader.EndOfStream)
				{
					read = steamReader.Read();
					Console.Write((char)read);
				}
				Console.WriteLine("\r\n--END--");
				stream.Close();
				socket.Close();
			}
			catch (Exception exc)
			{
				Console.WriteLine(exc.Message + "\r\n" + exc.StackTrace);
			}
			Console.WriteLine("Press ENTER to continue...");
			Console.Read();
		}
	}
}
Edited by Periander

Share this post


Link to post
Share on other sites

It's been a while, a few years, so I'll see how I go....

 

e: ah sorry. I see you're listening on port 22222. :) can't be bothered deleting what I wrote below.

 

TcpListener is definitely for 1 end point. As the name suggests, it listens for connections, that is, is used for the server part. It's also a synchronous socket and not much good for anything "industrial" or "enterprisey" :) And that's because you're only getting one connection, so if making a web server using TcpListener is going to suck :)

You didn't say what port you're going to listen on. End point = port and IP. You could already be listening on the port you're trying to use. (like port 80 or 443 or 25 or whatever).

 

From memory listener.Socket() will block until there's a connection, at which point AcceptSocket() gives you that connection and you can use it to send data to the client.

 

Generally you want to listen on a non-blocking socket and raise an even when a connection is ready. you then take that connection and store it in a list, or other structure. My preference (until WCF came along and abstracted tcp sockets for me :)) was to use the lower level, Socket class for both listening and connecting in. So yeah, basically for a server you have a async socket raising an event when a client socket connects. You then take that connection (referece to a client end point) and store it in a data structure. When the server needs to send to the clients it iterates over the list calling Send on each stored connection. that's if you're maintaining a permanent connection. While TCP connection is supposed to be permanent, you'll also need to send occasional "heartbeats" (which are just tiny packets of data) down the connection to keep it open. Otherwise hardware (routers and whatnot) may close the connection.

 

 

Ah good fun... learnt from years of designing and developing "enterprise" distributed systems that communicated using proprietary protocols (designed in house) over TCP.

Edited by kikz

Share this post


Link to post
Share on other sites

Thanks for the advice kikz, it has given me a bit to think about.

 

I'm not actually using TcpListener, but I used it in the test app for simplicity.

 

I've just been using Socket, binding that to an EndPoint, Listening, then BeginAccept to asynchronously read the stream. Basically just regurgitated MS code.

 

I actually found the same problem in both though in that I had could not specify IPv4 because of a permissions issue, and that when I specified the IPv6 address ::1, with my client I could only connect to the socket by using the address ::1; which doesn't seem right to me, (I thought that the listener would simply be bound to a port, not an end point, and that any connection to that port would be handled).

Share this post


Link to post
Share on other sites

Nevermind; I already had something on that port. :S

 

Edit: 0.0.0.0 is working as a generic ip address for end points, (i.e., all connections that come in to this PC with port number 22222).

Edited by Periander

Share this post


Link to post
Share on other sites

Nevermind; I already had something on that port. :S

:) that was my first guess 'cause the code looks ok.

Share this post


Link to post
Share on other sites

(I thought that the listener would simply be bound to a port, not an end point, and that any connection to that port would be handled).

ipv 6 and 4 are stateless protocol.

Looks to me like you waved your hand at it so it waved its back.

Edited by nicephotog-jvm.net

Share this post


Link to post
Share on other sites

(I thought that the listener would simply be bound to a port, not an end point, and that any connection to that port would be handled).

ipv 6 and 4 are stateless protocol.

Looks to me like you waved your hand at it so it waved its back.

 

As I said, I'm a little rusty on networking. I've managed to get it to work though; if I make my end point 0.0.0.0:22222, it works and my external client can connect and communication to it via the 'real' IP address.

Edited by Periander

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×