揭开Socket面纱

Socket是什么?

Socket是应用层与TCP/IP协议通信的中间软件抽象层,其实Socket就是一组接口。其实Socket就是把TCP/IP协议族隐藏在Socket接口后面,对程序员来说,可能你不懂这些复杂的TCP/IP协议族,那么实现接口就可以进行简单的Socket通信了,Socket会去组织数据,以符合指定的协议。


一个生活中的场景:你需要和一个朋友进行通话,你就要拨号,通过运营商接通到你朋友的手机,你朋友听到电话铃声并接听电话,这样你和你的朋友就建立了连接,你们就可以进行通信了。其实Socket通信原理也是如此。我们先看下图:
Socket
这有一个服务器端和一个客户端,服务器端就相当于你,客户端就相当与你的朋友。服务器端初始化Socket,然后与端口绑定(bind),然后对端口监听(listen),调用accept进行阻塞,等待客户端的连接。当你的朋友接通电话时,就相当与客户端初始化了一个Socket,然后连接(connect)服务器,如果连接成功,这是客户端与服务器端就建立的连接。客户端发送发送了数据,服务器端接受并处理请求,然后把回应数据返还个客户端,客户端读取数据后,然后关闭连接,一次连接就结束了。


C#中的Socket编程

常用的类和方法

在进行编写代码之前,我们先看几个常用的类和方法,这会使我们的学习事半功倍。

  • IPAddress类
    这是一个IP地址操作类,构造一个IP地址对象IPAddress的构造函数是 IPAddress(long adress),但是通常情况下我们使用该类中的Parse( )方法,可以把点分的十进制IP表示转化成IPAddress类。如:

    IPAddress address = IPAddress.Parse(“127.0.0.1”);

另外还有一种初始化IP地址的方法,该类中提供的只读字段IPAddress.Any: 使用你机器上热河一个可用ip来初始化这个IP地址对象。IPAddress中还提供了另外3个只读字段:

   IPAddress.Broadcase //用于代表本地网络的IP广播地址 
   IPAddress.Loopback 用于代表系统的回送地址    
   IPAddress.None 用于代表系统上没有网络接口
  • IPEndPoint类

IPEndPoint其实就是一个IP地址和端口的绑定,可以代表一个服务,用来Socket通讯。
我们可以通过2种构造方法来创建IPEndPoint类:

IPEndPoint(long address, int port)
IPEndPoint(IPAddress address, int port)
  • DNS相关类

DNS类有四个静态方法,来获取主机DNS相关信息,

  • GetHostName()

通过Dns.GetHostName()可以获得本地计算机的主机名

  • GetHostByName()

根据主机名称,返回一个IPHostEntry 对象:

  IPHostEntry GetHostByName(string hostName) 

其中IPHostEntry把一个DNS主机名与一个别名和IP地址的数组相关联,包含三个属性:
AddressList:一个IPAddress对象的数组
Aliases:一个字符串对象数组
HostName:一个用于主机名的字符串对象

  • GetHostByAddress()
    类似于GetHostByName(),只不过这里的参数是IP地址,而不是主机名,也返回一个IPHostEntry对象。

    IPHostEntry GetHostByAddress(IPAddress address)
    IPHostEntry GetHostByAddress(string address)

  • Resolve()
    当我们不知道输入的远程主机的地址是哪种格式(主机名或IP地址)时,用以上二种方法来实现,我们可能还要通过判断客户输入的格式,才能正确使用,但dns类提供一更简单的方法Resolve(),该方法可以接受主机名格式或IP地址格式的任何一种地址,并返回IPHostEntry对象。

Socket编程

服务器端

就如我们上面所说,服务器端创建Socket连接的步骤有:初始化Socket,然后与端口绑定(bind),然后对端口监听(listen),调用accept进行阻塞,等待客户端的连接。

namespace Server
{
    class Server
    {
        static void Main ( string[] args )
        {

            int port = 6001;
            string host = "127.0.0.1";
            IPAddress ipAddress = IPAddress.Parse ( host );
            //创建IPEndPoint实例,用于Scoket监听
            IPEndPoint ipep = new IPEndPoint ( ipAddress, port );

            //创建套接字实例
            //这里使用ProtocolType.Tcp,表示建立一个面向连接的Scoket.如果要用UDP协议要用SocketType.Dgram
            Socket serverSocket = new Socket ( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
            //将所创建的套接字与IPEndPoint绑定
            serverSocket.Bind ( ipep );

            //设置套接字为监听模式,并且挂起队列最长为10
            serverSocket.Listen ( 10 );

            Console.WriteLine ( "等待客户端连接" );


            //接收到client连接,为此链接创建新的socket,并接收信息
            Socket tempSocket = serverSocket.Accept ( );
            Console.WriteLine ( "建立连接");


            while (tempSocket.Connected)
            {
                string recvString = "";
                byte[] recvByte = new byte[1024];
                int byteCount;
                byteCount = tempSocket.Receive ( recvByte, recvByte.Length, 0 );
                recvString += Encoding.ASCII.GetString ( recvByte, 0, byteCount );//将字节编码解释为字符串

                //给client返回信息
                Console.WriteLine ( "服务器得到的信息:{0}", recvString );

                string sendString = "got message";
                byte[] bytesSend = Encoding.ASCII.GetBytes ( sendString );

                tempSocket.Send ( bytesSend, bytesSend.Length, 0 );//返回客户端信息
            }

            tempSocket.Close ( );
            serverSocket.Close ( );



            Console.ReadLine ( );

        }
    }
}

通过serverSocket.Accept()来接收客户Socket的连接请求,在这里用循环可以实现该线程实时侦听,而不是只侦听一次。当程序运行serverSocket.Accept()时,会等待,直到有客户端Socket发起连接请求时,获取该客户Socket。

客户端

同样的客户端初始化一个Socket,然后连接(connect)服务器,如果连接成功,这是客户端与服务器端就建立的连接。客户端发送发送了数据,服务器端接受并处理请求,然后把回应数据返还个客户端,客户端读取数据。

    namespace Client
{
    class Client
    {
        static void Main ( string[] args )
        {
            try
            {
                int port = 6001;
                string host = "127.0.0.1";

                IPAddress ip = IPAddress.Parse ( host );
                IPEndPoint ipe = new IPEndPoint ( ip, port );

                //创建socket并连接服务器

                Socket clientSocket = new Socket ( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );

                Console.WriteLine ( "connect..." );
                clientSocket.Connect ( ipe );
                int count = 0;
                do
                {
                    //向服务器发送信息
                    string sendString = Console.ReadLine ( );//"this is a test";
                        byte[] sendByte = Encoding.ASCII.GetBytes ( sendString );
                    Console.WriteLine ( "send message" );
                    clientSocket.Send ( sendByte, sendByte.Length, 0 );

                    //接受服务器返回的信息

                    string recvString = "";

                    byte[] recvByte = new Byte[1024];
                    int bytesCount;
                    bytesCount = clientSocket.Receive ( recvByte, recvByte.Length, 0 );

                    recvString += Encoding.ASCII.GetString ( recvByte, 0, bytesCount );

                    Console.WriteLine ( "client get : {0}", recvString );
                    count ++;
                }while(count < 10);

                clientSocket.Close ( );



            }
            catch (ArgumentNullException e)
            {
                Console.WriteLine ( "argumentNullException:{0}", e );

            }
            catch (SocketException e) {
                Console.WriteLine ("SocketException:{0}",e);
            }
            Console.ReadLine (  );
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值