zoukankan      html  css  js  c++  java
  • Socket接口原理及用C#语言实现

    首先从原理上解释一下采用Socket接口的网络通讯,这里以最常用的C/S模式作为范例,首先,服务端有一个进程(或多个进程)在指定的端口等待客户来连接,服务程序等待客户的连接信息,一旦连接上之后,就可以按设计的数据交换方法和格式进行数据传输。客户端在需要的时刻发出向服务端的连接请求。这里为了便于理解,提到了一些调用及其大致的功能。使用socket调用后,仅产生了一个可以使用的socket描述符,这时还不能进行通信,还要使用其他的调用,以使得socket所指的结构中使用的信息被填写完。

      在使用TCP协议时,一般服务端进程先使用socket调用得到一个描述符,然后使用bind调用将一个名字与socket描述符连接起来,对于Internet域就是将Internet地址联编到socket。之后,服务端使用listen调用指出等待服务请求队列的长度。然后就可以使用accept调用等待客户端发起连接,一般是阻塞等待连接,一旦有客户端发出连接,accept返回客户的地址信息,并返回一个新的socket描述符,该描述符与原先的socket有相同的特性,这时服务端就可以使用这个新的socket进行读写操作了。一般服务端可能在accept返回后创建一个新的进程进行与客户的通信,父进程则再到accept调用处等待另一个连接。客户端进程一般先使用socket调用得到一个socket描述符,然后使用connect向指定的服务器上的指定端口发起连接,一旦连接成功返回,就说明已经建立了与服务器的连接,这时就可以通过socket描述符进行读写操作了。

    .NetFrameWork为Socket通讯提供了System.NET.Socket命名空间,在这个命名空间里面有以下几个常用的重要类分别是:

      ·Socket类 这个底层的类用于管理连接,WebRequest,TcpClient和UdpClient在内部使用这个类。

      ·NetworkStream类 这个类是从Stream派生出来的,它表示来自网络的数据流

      ·TcpClient类 允许创建和使用TCP连接

      ·TcpListener类 允许监听传入的TCP连接请求

      ·UdpClient类 用于UDP客户创建连接(UDP是另外一种TCP协议,但没有得到广泛的使用,主要用于本地网络

    下面我们来看一个基于Socket的双机通信代码的C#版本

    首先创建Socket对象的实例,这可以通过Socket类的构造方法来实现:

    1. public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolType);   

    其中,addressFamily 参数指定 Socket 使用的寻址方案,socketType 参数指定 Socket 的类型,protocolType 参数指定 Socket 使用的协议。

    下面的示例语句创建一个 Socket,它可用于在基于 TCP/IP 的网络(如 Internet)上通讯。

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

    若要使用 UDP 而不是 TCP,需要更改协议类型,如下面的示例所示:

    1. Socket temp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);   

    一旦创建 Socket,在客户端,你将可以通过Connect方法连接到指定的服务器(你可以在Connect方法前Bind端口,就是以指定的端口发起连接,如果不事先Bind端口号的话,系统会默认在1024到5000随机绑定一个端口号),并通过Send方法向远程服务器发送数据,而后可以通过Receive从服务端接收数据;而在服务器端,你需要使用Bind方法绑定所指定的接口使Socket与一个本地终结点相联,并通过Listen方法侦听该接口上的请求,当侦听到用户端的连接时,调用Accept完成连接的操作,创建新的Socket以处理传入的连接请求。使用完 Socket 后,使用 Close 方法关闭 Socket。

      可以看出,以上许多方法包含EndPoint类型的参数,在Internet中,TCP/IP 使用一个网络地址和一个服务端口号来唯一标识设备。网络地址标识网络上的特定设备;端口号标识要连接到的该设备上的特定服务。网络地址和服务端口的组合称为终结点,在 .NET 框架中正是由 EndPoint 类表示这个终结点,它提供表示网络资源或服务的抽象,用以标志网络地址等信息。.Net同时也为每个受支持的地址族定义了 EndPoint 的子代;对于 IP 地址族,该类为 IPEndPoint。IPEndPoint 类包含应用程序连接到主机上的服务所需的主机和端口信息,通过组合服务的主机IP地址和端口号,IPEndPoint 类形成到服务的连接点。

    用到IPEndPoint类的时候就不可避免地涉及到计算机IP地址,System.net命名空间中有两种类可以得到IP地址实例:

    ·IPAddress类:IPAddress 类包含计算机在 IP 网络上的地址。其Parse方法可将 IP 地址字符串转换为 IPAddress 实例。下面的语句创建一个 IPAddress 实例:

    1. IPAddress myIP = IPAddress.Parse("192.168.0.1");   

    需要知道的是:Socket 类支持两种基本模式:同步和异步。其区别在于:在同步模式中,按块传输,对执行网络操作的函数(如 Send 和 Receive)的调用一直等到所有内容传送操作完成后才将控制返回给调用程序。在异步模式中,是按位传输,需要指定发送的开始和结束。同步模式是最常用的模式,我们这里的例子也是使用同步模式。

    //client端

    using System;
    using System.Text;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    namespace socketsample
    {
     class Class1
     {
      static void Main()
      {
       try
       {
        int port = 2000;
        string host = "127.0.0.1";
        IPAddress ip = IPAddress.Parse(host);
        IPEndPoint ipe = new IPEndPoint(ip, port);//把ip和端口转化为IPEndPoint实例
        Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建一个Socket
        Console.WriteLine("Conneting...");
        c.Connect(ipe);//连接到服务器
        string sendStr = "hello!This is a socket test";
        byte[] bs = Encoding.ASCII.GetBytes(sendStr);
        Console.WriteLine("Send Message");
        c.Send(bs, bs.Length, 0);//发送测试信息
        string recvStr = "";
        byte[] recvBytes = new byte[1024];
        int bytes;
        bytes = c.Receive(recvBytes, recvBytes.Length, 0);//从服务器端接受返回信息
        recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
        Console.WriteLine("Client Get Message:{0}", recvStr);//显示服务器返回信息
        c.Close();
       }
       catch (ArgumentNullException e)
       {
        Console.WriteLine("ArgumentNullException: {0}", e);
       }
       catch (SocketException e)
       {
        Console.WriteLine("SocketException: {0}", e);
       }
       Console.WriteLine("Press Enter to Exit");
       Console.ReadLine();
      }
     }
    }

    //server端

    using System;
    using System.Text;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    namespace Project1
    {
     class Class2
     {
      static void Main()
      {
       try
       {
        int port = 2000;
        string host = "127.0.0.1";
        IPAddress ip = IPAddress.Parse(host);
        IPEndPoint ipe = new IPEndPoint(ip, port);
        Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建一个Socket类
        s.Bind(ipe);//绑定2000端口
        s.Listen(0);//开始监听
        Console.WriteLine("Wait for connect");
        Socket temp = s.Accept();//为新建连接创建新的Socket。
        Console.WriteLine("Get a connect");
        string recvStr = "";
        byte[] recvBytes = new byte[1024];
        int bytes;
        bytes = temp.Receive(recvBytes, recvBytes.Length, 0);//从客户端接受信息
        recvStr += Encoding.ASCII.GetString(recvBytes, 0, bytes);
        Console.WriteLine("Server Get Message:{0}",recvStr);//把客户端传来的信息显示出来
        string sendStr = "Ok!Client Send Message Sucessful!";
        byte[] bs = Encoding.ASCII.GetBytes(sendStr);
        temp.Send(bs, bs.Length, 0);//返回客户端成功信息
        temp.Close();
        s.Close();
       }
       catch (ArgumentNullException e)
       {
        Console.WriteLine("ArgumentNullException: {0}", e);
       }
       catch (SocketException e)
       {
        Console.WriteLine("SocketException: {0}", e);
       }
       Console.WriteLine("Press Enter to Exit");
       Console.ReadLine();
      }
     }
    }

    System.Net.Socket命名空间还提供了两个抽象高级类TCPClient和UDPClient和用于通讯流处理的NetWorkStream

    //client端

    TcpClient tcpClient=new TcpCLient(主机IP,端口号);
    NetworkStream ns=tcp.Client.GetStream();

    //server端 

    TcpListener tcpListener=new TcpListener(监听端口);
    tcpListener.Start();
    TcpClient tcpClient=tcpListener.AcceptTcpClient();
    NetworkStream ns=tcpClient.GetStream();

    服务端用TcpListener监听,然后把连接的对象实例化为一个TcpClient,调用TcpClient.GetStream()方法,返回网络流实例化为一个NetworlStream流,下面就是用流的方法进行Send,Receive

  • 相关阅读:
    elasticsearch 中的Multi Match Query
    activiti 流程部署的各种方式
    elasticsearch 嵌套对象之嵌套类型
    elasticsearch Java High Level REST 相关操作封装
    elasticsearch 字段数据类型
    ubuntu 安装 docker
    elasticsearch 通过HTTP RESTful API 操作数据
    facenet 人脸识别(二)——创建人脸库搭建人脸识别系统
    POJ 3093 Margaritas(Kind of wine) on the River Walk (背包方案统计)
    墨卡托投影, GPS 坐标转像素, GPS 坐标转距离
  • 原文地址:https://www.cnblogs.com/johnblogs/p/7087091.html
Copyright © 2011-2022 走看看