C# Socket网络编程精华篇

简介: 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的具体用法,效果图如下:

关键代码:

服务器端代码:

private void Form1_Load(object sender, EventArgs e)
        {
            Control.CheckForIllegalCrossThreadCalls = false;
        }
        private void btnListen_Click(object sender, EventArgs e)
        {
            //ip地址
            IPAddress ip = IPAddress.Parse(txtIP.Text);
           // IPAddress ip = IPAddress.Any;
            //端口号
            IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));
            //创建监听用的Socket
            /*
             * AddressFamily.InterNetWork:使用 IP4地址。
SocketType.Stream:支持可靠、双向、基于连接的字节流,而不重复数据。此类型的 Socket 与单个对方主机进行通信,并且在通信开始之前需要远程主机连接。Stream 使用传输控制协议 (Tcp) ProtocolType 和 InterNetworkAddressFamily。
ProtocolType.Tcp:使用传输控制协议。
             */
            //使用IPv4地址,流式socket方式,tcp协议传递数据
            Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
            //创建好socket后,必须告诉socket绑定的IP地址和端口号。
            //让socket监听point
            try
            {
                //socket监听哪个端口
                socket.Bind(point);
                //同一个时间点过来10个客户端,排队
                socket.Listen(10);
                ShowMsg("服务器开始监听");
                Thread thread = new Thread(AcceptInfo);
                thread.IsBackground = true;
                thread.Start(socket);
            }
            catch (Exception ex)
            {
               ShowMsg(ex.Message);
            }
        }
        //记录通信用的Socket
        Dictionary<string,Socket> dic=new Dictionary<string, Socket>();
       // private Socket client;
        void AcceptInfo(object o)
        {
            Socket socket = o as Socket;
            while (true)
            {
                //通信用socket
                try
                {
                    //创建通信用的Socket
                  Socket  tSocket = socket.Accept();
                  string point = tSocket.RemoteEndPoint.ToString();
                    //IPEndPoint endPoint = (IPEndPoint)client.RemoteEndPoint;
                    //string me = Dns.GetHostName();//得到本机名称
                    //MessageBox.Show(me);
                 ShowMsg(point + "连接成功!");
                 cboIpPort.Items.Add(point);
                 dic.Add(point, tSocket);
                    //接收消息
                    Thread th = new Thread(ReceiveMsg);
                    th.IsBackground = true;
                    th.Start(tSocket);
                }
                catch (Exception ex)
                {
                    ShowMsg(ex.Message);
                    break;
                }
            }
        }
        //接收消息
        void ReceiveMsg(object o)
        {
            Socket client = o as Socket;
            while (true)
            {
                //接收客户端发送过来的数据
                try
                {
                    //定义byte数组存放从客户端接收过来的数据
                    byte[] buffer = new byte[1024 * 1024];
                    //将接收过来的数据放到buffer中,并返回实际接受数据的长度
                    int n = client.Receive(buffer);
                    //将字节转换成字符串
                    string words = Encoding.UTF8.GetString(buffer, 0, n);
                    ShowMsg(client.RemoteEndPoint.ToString() + ":" + words);
                }
                catch (Exception ex)
                {
                   ShowMsg(ex.Message);
                    break;
                }
            }
        }
        void ShowMsg(string msg)
        {
            txtLog.AppendText(msg+"\r\n");
        }
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            //主窗体关闭时关闭子线程
        }
        //给客户端发送消息
        private void btnSend_Click(object sender, EventArgs e)
        {
            try
            {
                ShowMsg(txtMsg.Text);
                string ip = cboIpPort.Text;
                byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);
                dic[ip].Send(buffer);
                // client.Send(buffer);
            }
            catch (Exception ex)
            {
               ShowMsg(ex.Message);
            }
        }

客户端代码:

Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        private void btnConnection_Click(object sender, EventArgs e)
        {
            //连接到的目标IP
            IPAddress ip = IPAddress.Parse(txtIP.Text);
            //IPAddress ip = IPAddress.Any;
            //连接到目标IP的哪个应用(端口号!)
            IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));
            try
            {
                //连接到服务器
                client.Connect(point);
                ShowMsg("连接成功");
                ShowMsg("服务器" + client.RemoteEndPoint.ToString());
                ShowMsg("客户端:" + client.LocalEndPoint.ToString());
                //连接成功后,就可以接收服务器发送的信息了
                Thread th=new Thread(ReceiveMsg);
                th.IsBackground = true;
                th.Start();
            }
            catch (Exception ex)
            {
                ShowMsg(ex.Message);
            }
        }
        //接收服务器的消息
        void ReceiveMsg()
        {
            while (true)
            {
                try
                {
                    byte[] buffer = new byte[1024 * 1024];
                    int n = client.Receive(buffer);
                    string s = Encoding.UTF8.GetString(buffer, 0, n);
                    ShowMsg(client.RemoteEndPoint.ToString() + ":" + s);
                }
                catch (Exception ex)
                {
                    ShowMsg(ex.Message);
                    break;
                }
            }
        }
        void ShowMsg(string msg)
        {
            txtInfo.AppendText(msg+"\r\n");
        }
        private void btnSend_Click(object sender, EventArgs e)
        {
            //客户端给服务器发消息
            if (client!=null)
            {
                try
                {
                   ShowMsg(txtMsg.Text);
                    byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);
                    client.Send(buffer);
                }
                catch (Exception ex)
                {
                   ShowMsg(ex.Message);
                }
            }
        }
        private void ClientForm_Load(object sender, EventArgs e)
        {
            Control.CheckForIllegalCrossThreadCalls = false;
        }

好了,到这里我们对Socket的讨论就告一个段落了。希望以后还有时间来研究这方面的知识。因为我深深的知道,能和大家探讨也是一种幸福。

 

 

原文地址:https://www.cnblogs.com/weilengdeyu/archive/2013/03/08/2949101.html

 

此篇文章所述内容为简单的socket使用以及其原理,在大型项目中,需要采用长连接(保持连接的心跳包)来实现,

另外,文中demo的GitHub地址:https://github.com/lijt1993/socket

 

此外,还有2篇优秀博文可参考理解:

.net平台下C#socket通信(上)

.net平台下C#socket通信(中)

相关文章
|
2月前
|
C# 开发者
C# 一分钟浅谈:Socket 编程基础
【10月更文挑战第7天】本文介绍了Socket编程的基础知识、基本操作及常见问题,通过C#代码示例详细展示了服务器端和客户端的Socket通信过程,包括创建、绑定、监听、连接、数据收发及关闭等步骤,帮助开发者掌握Socket编程的核心技术和注意事项。
104 3
C# 一分钟浅谈:Socket 编程基础
|
2月前
|
消息中间件 网络协议 C#
C#使用Socket实现分布式事件总线,不依赖第三方MQ
`CodeWF.EventBus.Socket` 是一个轻量级的、基于Socket的分布式事件总线系统,旨在简化分布式架构中的事件通信。它允许进程之间通过发布/订阅模式进行通信,无需依赖外部消息队列服务。
C#使用Socket实现分布式事件总线,不依赖第三方MQ
|
1月前
|
Kubernetes 网络协议 Python
Python网络编程:从Socket到Web应用
在信息时代,网络编程是软件开发的重要组成部分。Python作为多用途编程语言,提供了从Socket编程到Web应用开发的强大支持。本文将从基础的Socket编程入手,逐步深入到复杂的Web应用开发,涵盖Flask、Django等框架的应用,以及异步Web编程和微服务架构。通过本文,读者将全面了解Python在网络编程领域的应用。
35 1
|
2月前
|
Java
[Java]Socket套接字(网络编程入门)
本文介绍了基于Java Socket实现的一对一和多对多聊天模式。一对一模式通过Server和Client类实现简单的消息收发;多对多模式则通过Server类维护客户端集合,并使用多线程实现实时消息广播。文章旨在帮助读者理解Socket的基本原理和应用。
31 1
|
2月前
|
消息中间件 监控 网络协议
Python中的Socket魔法:如何利用socket模块构建强大的网络通信
本文介绍了Python的`socket`模块,讲解了其基本概念、语法和使用方法。通过简单的TCP服务器和客户端示例,展示了如何创建、绑定、监听、接受连接及发送/接收数据。进一步探讨了多用户聊天室的实现,并介绍了非阻塞IO和多路复用技术以提高并发处理能力。最后,讨论了`socket`模块在现代网络编程中的应用及其与其他通信方式的关系。
233 3
|
1月前
|
网络协议 Unix Linux
精选2款C#/.NET开源且功能强大的网络通信框架
精选2款C#/.NET开源且功能强大的网络通信框架
|
2月前
|
网络协议 Linux 应用服务中间件
Socket通信之网络协议基本原理
【10月更文挑战第10天】网络协议定义了机器间通信的标准格式,确保信息准确无损地传输。主要分为两种模型:OSI七层模型与TCP/IP模型。
|
3月前
|
网络协议 开发者 Python
网络编程小白秒变大咖!Python Socket基础与进阶教程,轻松上手无压力!
在网络技术飞速发展的今天,掌握网络编程已成为开发者的重要技能。本文以Python为工具,带你从Socket编程基础逐步深入至进阶领域。首先介绍Socket的概念及TCP/UDP协议,接着演示如何用Python创建、绑定、监听Socket,实现数据收发;最后通过构建简单的聊天服务器,巩固所学知识。让初学者也能迅速上手,成为网络编程高手。
83 1
|
2月前
|
网络协议 测试技术 网络安全
Python编程-Socket网络编程
Python编程-Socket网络编程
29 0
|
3月前
|
网络协议
关于套接字socket的网络通信。&聊天系统 聊天软件
关于套接字socket的网络通信。&聊天系统 聊天软件