• C# Socket编程


    我们在讲解Socket编程前,先看几个和Socket编程紧密相关的概念:

    1. TCP/IP层次模型

        当然这里我们只讨论重要的四层

           01,应用层(Application):应用层是个很广泛的概念,有一些基本相同的系统级TCP/IP应用以及应用协议,也有许多的企业应用和互联网应用。http协议在应用层运行。

           02,传输层(Tanspot):传输层包括UDP和TCP,UDP几乎不对报文进行检查,而TCP

    提供传输保证。

          03,网络层(Netwok):网络层协议由一系列协议组成,包括ICMP、IGMP、RIP、OSPF、IP(v4,v6)等。

          04,链路层(Link):又称为物理数据网络接口层,负责报文传输。

       然后我们来看下tcp层次模型图

     

         从上图中可以看出,应用程序在应用层运行,在传输层,在数据前加上了TCP头,在

    网络层加上的IP头,在数据链路层加上了帧。

       2,端口

        端口号范围:0-65535,总共能表示65536个数。

       按端口号可分为3大类

      (1)公认端口(WellKnownPorts):从0到1023,它们紧密绑定(binding)于一些服务。通常这些端口的通讯明确表明了某种服务的协议。例如:80端口实际上总是HTTP通讯。

      (2)注册端口(RegisteredPorts):从1024到49151。它们松散地绑定于一些服务。也就是说有许多服务绑定于这些端口,这些端口同样用于许多其它目的。例如:许多系统处理动态端口从1024左右开始。

      (3)动态和/或私有端口(Dynamicand/orPrivatePorts):从49152到65535。理论上,不应为服务分配这些端口。实际上,机器通常从1024起分配动态端口。

    3.TCP和UDP报文

      下面一起来看下TCP和UDP的报文图

     

          从图中我们可以看出TCP和UDP中都有校验和,但是在UDP报文中,一般不使用校验和,这样可以加快数据传输的速度,但是数据的准确性可能会受到影响。换句话说,Tcp协议都有校验和,为了保证传输数据的准确性。

    3.Socket

         Socket包括Ip地址和端口号两部分,程序通过Socket来通信,Socket相当于操作系统的一个组件。Socket作为进程之间通信机制,通常也称作”套接字”,用于描述IP地址和端口号,是一个通信链的句柄。说白了,就是两个程序通信用的。

    生活案例对比:

          Socket之间的通信可以类比生活中打电话的案例。任何用户在通话之前,首先要占有一部电话机,相当于申请一个Socket,同时要知道对方的号码,相当于对方有一个固定的Socket,然后向对方拨号呼叫,相当于发出连接请求。假如对方在场并空闲,拿起 电话话筒,双方就可以进行通话了。双方的通话过程,是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket发送数据和从socket接收数据。通话结束后,一方挂起电话机,相当于关闭socket,撤销连接。

         注意:Socket不仅可以在两台电脑之间通信,还可以在同一台电脑上的两个程序间通信。

    4,端口进阶(深入)

        通过IP地址确定了网络中的一台电脑后,该电脑上可能提供很多提供服务的应用,每一个应用都对应一个端口。

    在Internet上有很多这样的主机,这些主机一般运行了多个服务软件 ,同时提供几种服务,每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应用程序)

        例如:http 使用80端口,   ftp使用21端口     smtp使用25端口

    5.Socket分类

         Socket主要有两种类型:

    1. 流式Socket

              是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低

         2,数据报式Socket

              是一种无连接的Socket,对应于无连接的UDP服务应用,不安全,但效率高

     6. Socket一般应用模式(服务器端和客户端)

         服务器端的Socket(至少需要两个)

            01.一个负责接收客户端连接请求(但不负责与客户端通信)

           02.每成功接收到客户端的连接便在服务器端产生一个对应的复杂通信的Socket

              021.在接收到客户端连接时创建

             022. 为每个连接成功的客户端请求在服务器端都创建一个对应的Socket(负责和客户端通信)

        客户端的Socket

    1. 必须指定要连接的服务器地址和端口
    2. 通过创建一个Socket对象来初始化一个到服务器端的TCP连接

     

          通过上图,我们可以看出,首先服务器会创建一个负责监听的socket,然后客户端通过socket连接到服务器指定端口,最后服务器端负责监听的socket,监听到客户端有连接过来了,就创建一个负责和客户端通信的socket。

    下面我们来看下Socket更具体的通信过程:

    Socket的通讯过程

      服务器端:

        01,申请一个socket

        02,绑定到一个IP地址和一个端口上

        03,开启侦听,等待接收连接

      客户端:

        01,申请一个socket

       02,连接服务器(指明IP地址和端口号)

       服务器端接收到连接请求后,产生一个新的socket(端口大于1024)与客户端建立连接并进行通信,原监听socket继续监听。

      注意:负责通信的Socket不能无限创建,创建的数量和操作系统有关。

     7.Socket的构造函数

        Public Socket(AddressFamily addressFamily,SocketType  socketType,ProtocolType  protocolTYpe)

        AddressFamily:指定Socket用来解析地址的寻址方案。例如:InterNetWork指示当Socket使用一个IP版本4地址连接

       SocketType:定义要打开的Socket的类型

       Socket类使用ProtocolType枚举向Windows  Sockets  API通知所请求的协议

    注意:

       1,端口号必须在 1 和 65535之间,最好在1024以后。

       2,要连接的远程主机必须正在监听指定端口,也就是说你无法随意连接远程主机。

    如:

    IPAddress addr = IPAddress.Parse("127.0.0.1");

    IPEndPoint endp = new IPEndPoint(addr,,9000);

             服务端先绑定:serverWelcomeSocket.Bind(endp)

             客户端再连接:clientSocket.Connect(endp)

       3,一个Socket一次只能连接一台主机

       4,Socket关闭后无法再次使用

      5,每个Socket对象只能与一台远程主机连接。如果你想连接到多台远程主机,你必须创建多个Socket对象。

    8.Socket常用类和方法

      相关类:

       IPAddress:包含了一个IP地址

       IPEndPoint:包含了一对IP地址和端口号

     方法:

       Socket():创建一个Socket

       Bind():绑定一个本地的IP和端口号(IPEndPoint)

       Listen():让Socket侦听传入的连接吃那个病,并指定侦听队列容量

       Connect():初始化与另一个Socket的连接

       Accept():接收连接并返回一个新的Socket

       Send():输出数据到Socket

       Receive():从Socket中读取数据

       Close():关闭Socket,销毁连接

      接下来,我们同一个简单的服务器和客户端通信的案例,来看下Sokcet的具体用法,效果图如下:

     

    关键代码:

    服务器端代码:

    复制代码
      1 private void Form1_Load(object sender, EventArgs e)
      2 
      3         {
      4 
      5             Control.CheckForIllegalCrossThreadCalls = false;
      6 
      7         }
      8 
      9  
     10 
     11         private void btnListen_Click(object sender, EventArgs e)
     12 
     13         {
     14 
     15             //ip地址
     16 
     17             IPAddress ip = IPAddress.Parse(txtIP.Text);
     18 
     19            // IPAddress ip = IPAddress.Any;
     20 
     21             //端口号
     22 
     23             IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));
     24 
     25             //创建监听用的Socket
     26 
     27             /*
     28 
     29              * AddressFamily.InterNetWork:使用 IP4地址。
     30 
     31 SocketType.Stream:支持可靠、双向、基于连接的字节流,而不重复数据。此类型的 Socket 与单个对方主机进行通信,并且在通信开始之前需要远程主机连接。Stream 使用传输控制协议 (Tcp) ProtocolType 和 InterNetworkAddressFamily。
     32 
     33 ProtocolType.Tcp:使用传输控制协议。
     34 
     35              */
     36 
     37             //使用IPv4地址,流式socket方式,tcp协议传递数据
     38 
     39             Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
     40 
     41             //创建好socket后,必须告诉socket绑定的IP地址和端口号。
     42 
     43             //让socket监听point
     44 
     45             try
     46 
     47             {
     48 
     49                 //socket监听哪个端口
     50 
     51                 socket.Bind(point);
     52 
     53                 //同一个时间点过来10个客户端,排队
     54 
     55                 socket.Listen(10);
     56 
     57                 ShowMsg("服务器开始监听");
     58 
     59                 Thread thread = new Thread(AcceptInfo);
     60 
     61                 thread.IsBackground = true;
     62 
     63                 thread.Start(socket);
     64 
     65             }
     66 
     67             catch (Exception ex)
     68 
     69             {
     70 
     71                
     72 
     73                ShowMsg(ex.Message);
     74 
     75             }
     76 
     77         }
     78 
     79         //记录通信用的Socket
     80 
     81         Dictionary<string,Socket> dic=new Dictionary<string, Socket>();
     82 
     83        // private Socket client;
     84 
     85         void AcceptInfo(object o)
     86 
     87         {
     88 
     89             Socket socket = o as Socket;
     90 
     91             while (true)
     92 
     93             {
     94 
     95                 //通信用socket
     96 
     97                 try
     98 
     99                 {
    100 
    101                     //创建通信用的Socket
    102 
    103                   Socket  tSocket = socket.Accept();
    104 
    105                   string point = tSocket.RemoteEndPoint.ToString();
    106 
    107                     //IPEndPoint endPoint = (IPEndPoint)client.RemoteEndPoint;
    108 
    109                     //string me = Dns.GetHostName();//得到本机名称
    110 
    111                     //MessageBox.Show(me);
    112 
    113                  ShowMsg(point + "连接成功!");
    114 
    115                  cboIpPort.Items.Add(point);
    116 
    117                  dic.Add(point, tSocket);
    118 
    119                     //接收消息
    120 
    121                     Thread th = new Thread(ReceiveMsg);
    122 
    123                     th.IsBackground = true;
    124 
    125                     th.Start(tSocket);
    126 
    127                 }
    128 
    129                 catch (Exception ex)
    130 
    131                 {
    132 
    133                     ShowMsg(ex.Message);
    134 
    135                     break;
    136 
    137                 }
    138 
    139             }
    140 
    141         }
    142 
    143         //接收消息
    144 
    145         void ReceiveMsg(object o)
    146 
    147         {
    148 
    149             Socket client = o as Socket;
    150 
    151             while (true)
    152 
    153             {
    154 
    155                 //接收客户端发送过来的数据
    156 
    157                 try
    158 
    159                 {
    160 
    161                     //定义byte数组存放从客户端接收过来的数据
    162 
    163                     byte[] buffer = new byte[1024 * 1024];
    164 
    165                     //将接收过来的数据放到buffer中,并返回实际接受数据的长度
    166 
    167                     int n = client.Receive(buffer);
    168 
    169                     //将字节转换成字符串
    170 
    171                     string words = Encoding.UTF8.GetString(buffer, 0, n);
    172 
    173                   
    174 
    175                     ShowMsg(client.RemoteEndPoint.ToString() + ":" + words);
    176 
    177                 }
    178 
    179                 catch (Exception ex)
    180 
    181                 {
    182 
    183                    ShowMsg(ex.Message);
    184 
    185                     break;
    186 
    187                 }
    188 
    189             }
    190 
    191         }
    192 
    193  
    194 
    195         void ShowMsg(string msg)
    196 
    197         {
    198 
    199             txtLog.AppendText(msg+"
    ");
    200 
    201         }
    202 
    203  
    204 
    205         private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    206 
    207         {
    208 
    209             //主窗体关闭时关闭子线程
    210 
    211           
    212 
    213         }
    214 
    215         //给客户端发送消息
    216 
    217         private void btnSend_Click(object sender, EventArgs e)
    218 
    219         {
    220 
    221             try
    222 
    223             {
    224 
    225                 ShowMsg(txtMsg.Text);
    226 
    227                 string ip = cboIpPort.Text;
    228 
    229                 byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);
    230 
    231                 dic[ip].Send(buffer);
    232 
    233                 // client.Send(buffer);
    234 
    235             }
    236 
    237             catch (Exception ex)
    238 
    239             {
    240 
    241                ShowMsg(ex.Message);
    242 
    243             }
    244 
    245  
    246 
    247         }
    复制代码

    客户端代码:

    复制代码
      1 Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      2 
      3         private void btnConnection_Click(object sender, EventArgs e)
      4 
      5         {
      6 
      7             //连接到的目标IP
      8 
      9             IPAddress ip = IPAddress.Parse(txtIP.Text);
     10 
     11             //IPAddress ip = IPAddress.Any;
     12 
     13             //连接到目标IP的哪个应用(端口号!)
     14 
     15             IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));
     16 
     17             try
     18 
     19             {
     20 
     21                 //连接到服务器
     22 
     23                 client.Connect(point);
     24 
     25                 ShowMsg("连接成功");
     26 
     27                 ShowMsg("服务器" + client.RemoteEndPoint.ToString());
     28 
     29                 ShowMsg("客户端:" + client.LocalEndPoint.ToString());
     30 
     31                 //连接成功后,就可以接收服务器发送的信息了
     32 
     33                 Thread th=new Thread(ReceiveMsg);
     34 
     35                 th.IsBackground = true;
     36 
     37                 th.Start();
     38 
     39             }
     40 
     41             catch (Exception ex)
     42 
     43             {
     44 
     45                 ShowMsg(ex.Message);
     46 
     47             }
     48 
     49         }
     50 
     51         //接收服务器的消息
     52 
     53         void ReceiveMsg()
     54 
     55         {
     56 
     57             while (true)
     58 
     59             {
     60 
     61                 try
     62 
     63                 {
     64 
     65                     byte[] buffer = new byte[1024 * 1024];
     66 
     67                     int n = client.Receive(buffer);
     68 
     69                     string s = Encoding.UTF8.GetString(buffer, 0, n);
     70 
     71                     ShowMsg(client.RemoteEndPoint.ToString() + ":" + s);
     72 
     73                 }
     74 
     75                 catch (Exception ex)
     76 
     77                 {
     78 
     79                     ShowMsg(ex.Message);
     80 
     81                     break;
     82 
     83                 }
     84 
     85             }
     86 
     87           
     88 
     89         }
     90 
     91  
     92 
     93         void ShowMsg(string msg)
     94 
     95         {
     96 
     97             txtInfo.AppendText(msg+"
    ");
     98 
     99         }
    100 
    101  
    102 
    103         private void btnSend_Click(object sender, EventArgs e)
    104 
    105         {
    106 
    107             //客户端给服务器发消息
    108 
    109             if (client!=null)
    110 
    111             {
    112 
    113                 try
    114 
    115                 {
    116 
    117                    ShowMsg(txtMsg.Text);
    118 
    119                     byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);
    120 
    121                     client.Send(buffer);
    122 
    123                 }
    124 
    125                 catch (Exception ex)
    126 
    127                 {
    128 
    129                    ShowMsg(ex.Message);
    130 
    131                 }
    132 
    133             }
    134 
    135            
    136 
    137         }
    138 
    139  
    140 
    141         private void ClientForm_Load(object sender, EventArgs e)
    142 
    143         {
    144 
    145             Control.CheckForIllegalCrossThreadCalls = false;
    146 
    147         }
    复制代码

         

  • 相关阅读:
    教你一步一步做无线点餐项目(登录篇)
    用Android中的ActionBar来实现分页Title栏滑块效果
    IIS处理brower的一个页面请求(www.test.com/SX?a=1)的处理流程
    [转载]物化视图——数据仓库手册
    [WEB系统中的设计模式(暂时放在这里,看不大懂)]mvc在web系统中的模式与应用
    ORACLE的分布式管理
    C#中 中 A==B && C==D ? E: F语法的一点问题
    delete 和 truncate
    prototype.js开发者手册
    【一个不错的oracle数据库诊断例子,值得学习一下】Oracle数据库诊断案例redo log日志组处于高激活状态
  • 原文地址:https://www.cnblogs.com/aijiao/p/9959194.html
Copyright © 2020-2023  润新知