网络编程

using System;

using System.Collections.Generic;

using System.Text;

using System.Net;

using System.Threading;

using System.Net.Sockets;

namespace ConsoleApplication1

{

    public  class AddressHelper

    {

        /// <summary>

        /// 获取主机IPv4

        /// </summary>

        /// <returns></returns>

        public IPAddress[] GetLocalhostIPv4Address()

        {

            //获取主机名

            string localhostName = Dns.GetHostName();

            //通过主机名获取主机地址信息

            IPHostEntry host = Dns.GetHostEntry(localhostName);

            List<IPAddress> addresses = new List<IPAddress>();

            foreach (IPAddress ip in host.AddressList)

            {

                if (ip.AddressFamily==System.Net.Sockets.AddressFamily.InterNetwork)

                {

                    addresses.Add(ip);

                }

            }

            return addresses.ToArray();

        }

        /// <summary>

        /// 获取一个网络端点表示为IP地址和端口号

        /// </summary>

        /// <returns></returns>

        public  IPEndPoint GetRemoteMachineIPEndPoint()

        {

            IPEndPoint iep = null;

            try

            {

                Console.WriteLine("请输入远程主机的IP:");

                IPAddress address = IPAddress.Parse(Console.ReadLine());

                Console.WriteLine("请输入远程主机打开的端口号:");

                int port = Convert.ToInt32(Console.ReadLine());

                if (port > 65535 || port < 1024)

                {

                    throw new Exception("端口号应该在[1024,65535]之间");

                }

                //ip终结点

                iep = new IPEndPoint(address, port);

            }

                //将空引用传递

            catch (ArgumentNullException)

            {

                Console.WriteLine("输入数据有误!不允许空");

            }

                //数据格式不正确

            catch (FormatException)

            {

                Console.WriteLine("输入数据有误!格式不正确");

            }

            catch (Exception ex)

            {

                Console.WriteLine(ex.Message);

            }

            return iep;

        }

        /*1、我们可以使用哪个端口?

         * 在实际开发中,经常为某个网络服务动态指定一个端口,为了避免与某些重要的网络服务程序冲突(比如80端口固定为Web服务器使用的)

         * 通常要求这个端口位于[1024,65535]之间

         * 我们如何选取一个没有被占用的端口呢?     

         * IPAddress.Any这个特殊的地址可以派上用场,当一个套接字对象绑定一个IPAddress.Any对象时,windows会为其自动分配一个未被占用的端口号

         * 当套接字不在使用时被回收,可以重复使用

         * 由此可以得到思路:

         * 创建一个套接字对象,让他绑定到IPAddress.Any对象,提取系统分配给的端口,然后再销毁此套接字对象。

         * Socket对象实现了IDisposable接口所以使用using关键字来自动回收其占用的资源

         * 为了防止2个网络程序(或者2个线程)同时调用可用端口的情况吗?

         * 这时,无法保证此方法的两次调用一定返回不同的端口。如果两个 Socket 对象尝试绑定到同一个 IPEndPoint ,将会引发一个 SocketException 异步。

         * 为此,我们需要一个能跨越进程边界的线程同步手段。命名的互斥同步对象 Mutex 可以解决这个问题

         */

        /// <summary>

        /// 获取本机当前可用的端口号,此方法是线程安全的

        /// </summary>

        /// <returns></returns>

        public int GetOneAvailableInLocalhost()

        {

            Mutex mtx = new Mutex(false, "ConsoleApplication1.AddressHelper.GetOneAvailablePort");

            try

            {

                mtx.WaitOne();

                IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);

                using (Socket tempSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))

                {

                    tempSocket.Bind(ep);

                    IPEndPoint iep = tempSocket.LocalEndPoint as IPEndPoint;

                    return iep.Port;

                }

            }

            catch (Exception)

            {

 

                throw;

            }

            finally

            {

                mtx.ReleaseMutex();

            }

        }

    }

}

posted @ 2010-12-07 22:34  hailiang2013  阅读(120)  评论(0编辑  收藏  举报