C#开发之Socket网络编程TCP/IP层次模型、端口及报文等探讨

C#开发之Socket网络编程TCP/IP层次模型、端口及报文等探讨

简介

本文主要介绍使用C#进行Socket网络编程时,涉及到的TCP/IP协议中的各个层次模型、端口以及报文等内容,并提供两个基本示例进行说明。

TCP/IP协议层次模型

TCP/IP协议是网络通信的基础,它将网络通信分为许多层,每一层负责不同的任务。这些层从下往上分别是:物理层、数据链路层、网络层、传输层、应用层。

下面是这些层级及其任务的简单描述:

  • 物理层:定义网络的物理布局以及底层数据传输,如电流、电压等。

  • 数据链路层:负责在物理层上,根据MAC地址,完成节点之间的通信;将从网络层接收到的IP数据报组成帧,在物理层上传输。

  • 网络层:为数据通信提供路由、寻址、分包等服务,负责网间的数据传输,通过IP地址来唯一标识不同的设备。

  • 传输层:为上层协议提供可靠的端到端通信,并提供差错检测和重传等机制,常用的协议有TCP和UDP。

  • 应用层:我们编写的程序所用的协议,如HTTP、FTP、SMTP等。

Socket端口

在TCP/IP协议中,每个设备都有一个IP地址,但这个地址只是标识了设备,而没有标识一个应用程序。为了实现设备与设备之间的通信,需要一个能够分辨应用程序的标识,这个标识就是端口。

端口是一个16位的整数,范围从0到65535,其中0到1023是被保留的,一般作为著名的端口使用,如HTTP协议的80端口、FTP协议的21端口等;1024到65535是动态端口,由操作系统分配给应用程序使用。

Socket报文

Socket报文是进行网络通信时所传输的数据单元,可以理解为一段二进制数据流。在TCP/IP协议中,Socket报文主要有三部分组成:

  • IP头部:包含了发送方和接收方的IP地址,IP协议版本,以及一些与IP协议相关的控制字段。

  • TCP头部:包含了TCP协议的各种控制字段,如端口号、序列号和确认号等。

  • 数据段:将应用程序的数据流发送给TCP层,并分段传输。

示例一:Socket服务端及其客户端

下面是一个简单的Socket服务端和客户端程序实例,适用于 TCP/IP 协议:

  1. 服务端:
using System;  
using System.Net;  
using System.Net.Sockets;  
using System.Text;

class Program  
{  
    static void Main(string[] args)  
    {  
      try  
      {  
            IPAddress ipAd = IPAddress.Parse("127.0.0.1");  
            TcpListener myList=new TcpListener(ipAd, 8001);  

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

            while(true)  
            {  
                TcpClient client = myList.AcceptTcpClient();  
                Console.WriteLine("客户端已连接...");  

                NetworkStream netStream = client.GetStream();  
                byte[] bytes = new byte[1024];  
                int i = netStream.Read(bytes, 0, bytes.Length);  
                string data = Encoding.ASCII.GetString(bytes, 0, i);  
                Console.WriteLine("收到客户端消息: {0}", data);  

                string response = "谢谢连接我们,再见!";  
                byte[] message = Encoding.ASCII.GetBytes(response);  
                netStream.Write(message, 0, message.Length);  
                client.Close();  
            }  
            myList.Stop();  
        }  
        catch (Exception e)  
        {  
            Console.WriteLine("出现异常: {0}", e.ToString());  
        }  
   }
}  
  1. 客户端:
using System;  
using System.Net;  
using System.Net.Sockets;  
using System.Text;  

class Program  
{  
    static void Main(string[] args)  
    {  
        try  
        {  
            TcpClient tcpclnt = new TcpClient();  
            Console.WriteLine("向服务端发送连接请求......");  
            tcpclnt.Connect("127.0.0.1", 8001);  

            byte[] bytes = Encoding.ASCII.GetBytes("客户端发送的数据......");  
            NetworkStream stream = tcpclnt.GetStream();  
            stream.Write(bytes, 0, bytes.Length);  
            Console.WriteLine("向服务端发送消息: {0}", Encoding.ASCII.GetString(bytes, 0, bytes.Length));  

            bytes = new byte[1024];  
            int i = stream.Read(bytes, 0, bytes.Length);  
            Console.WriteLine("从服务端收到消息: {0}", Encoding.ASCII.GetString(bytes, 0, i));  

            tcpclnt.Close();  
        }  
        catch (Exception e)  
        {  
            Console.WriteLine("出现异常: {0}", e.ToString());  
        }  
    }  
}  

示例二:Socket异步通信

下面的示例演示一个异步的Socket服务器,它可以同时处理多个请求。

using System;  
using System.Net;  
using System.Net.Sockets;  
using System.Text;

class Program  
{  
    static int port = 8001;  
    static TcpListener listener = new TcpListener(IPAddress.Any, port);  

    static void Main(string[] args)  
    {  
        listener.Start();  
        Console.WriteLine("等待客户端连接...");

        var state = new StateObject();  

        while(true)  
        {  
            listener.BeginAcceptTcpClient(AcceptTcpClientCallback, state);  
            Console.WriteLine("正在等待下一个客户端连接...");  
        }  
    }  

    static void AcceptTcpClientCallback(IAsyncResult ar)  
    {  
        Console.WriteLine("客户端连接成功...");  

        var state = (StateObject)ar.AsyncState;  
        TcpClient client = listener.EndAcceptTcpClient(ar);   
        state.Client = client;  

        NetworkStream stream = state.Client.GetStream();  
        byte[] buffer = new byte[1024];  
        stream.BeginRead(buffer, 0, buffer.Length, ReadCallback, state);  
    }  

    static void ReadCallback(IAsyncResult ar)  
    {    
        var state = (StateObject)ar.AsyncState;  
        NetworkStream stream = state.Client.GetStream();  
        int length = stream.EndRead(ar);  

        string data = Encoding.ASCII.GetString(state.Buffer, 0, length);  
        Console.WriteLine("收到客户端消息:{0}", data);  

        byte[] responseBytes = Encoding.ASCII.GetBytes("谢谢友善的客户端!");  
        stream.BeginWrite(responseBytes, 0, responseBytes.Length, WriteCallback, state);  
    }

    static void WriteCallback(IAsyncResult ar)  
    {  
        var state = (StateObject)ar.AsyncState;  
        NetworkStream stream = state.Client.GetStream();  
        stream.EndWrite(ar);  
        stream.BeginRead(state.Buffer, 0, state.Buffer.Length, ReadCallback, state);  
    }
}  

class StateObject  
{  
    public TcpClient Client { get; set; }  

    public byte[] Buffer = new byte[1024];  
}  

上面的代码中,异步通信主要通过BeginXXX和EndXXX方法进行,回调函数则负责对数据进行处理和响应数据。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#开发之Socket网络编程TCP/IP层次模型、端口及报文等探讨 - Python技术站

(0)
上一篇 2023年6月7日
下一篇 2023年6月7日

相关文章

  • C# DataGridView添加新行的2个方法

    下面是详细讲解“C# DataGridView添加新行的2个方法”的完整攻略: 1. 使用数据绑定添加新行 使用DataGridView进行数据绑定时,可以通过添加数据源中的新数据来添加新行。下面是添加新行的步骤: 步骤 1:创建数据源 首先,我们需要创建一个数据源。下面是一个示例: var dataSource = new List<Product&…

    C# 2023年6月6日
    00
  • C# StackExchange.Redis 用法汇总

    C# StackExchange.Redis 用法汇总 StackExchange.Redis 是 StackExchange(Stack Overflow 所属公司)开发的一款 Redis 客户端库。它是基于 .NET Standard 的,所以可以在各种平台上使用。StackExchange.Redis 有着良好的性能和低延迟,被广泛使用。本文将详细介绍…

    C# 2023年6月3日
    00
  • C# 7.0 使用下划线忽略使用的变量的原因分析

    C#7.0使用下划线忽略使用的变量的原因分析 在C#7.0中,我们可以使用一个特殊的下划线符号(_)来忽略我们不需要使用的变量,这在代码中并不会引起编译器的警告或错误提示,那么为什么需要使用这个符号,本文将对此进行详细讲解。 忽略变量的原因 在我们的应用程序和代码中,常常会出现我们所不需要的变量、返回值或者方法参数,但在某种情况下,我们又不得不使用这些变量或…

    C# 2023年5月15日
    00
  • SQL Server中调用C#类中的方法实例(使用.NET程序集)

    在SQL Server中,可以使用CLR(Common Language Runtime)扩展来调用C#类中的方法实例。这里提供一个完整的攻略来演示如何在SQL Server中使用.NET程序集来调用C#类中的方法实例。 步骤一:创建.NET程序集 我们首先需要创建一个.NET程序集,其中包含一个C#类和一个方法实例。以下是一个示例程序集代码: using …

    C# 2023年5月31日
    00
  • .Net Core日志记录的核心机制

    .NET Core日志记录的核心机制 在.NET Core中,日志记录是一个非常重要的功能,可以帮助我们在应用程序中记录和跟踪事件。本攻略将介绍.NET Core日志记录的核心机制,并提供两个示例说明。 日志记录的核心机制 在.NET Core中,日志记录的核心机制包括以下几个部分: 1. ILogger ILogger是在.NET Core中记录日志的接口…

    C# 2023年5月17日
    00
  • C# Linq的Sum()方法 – 计算序列中元素的总和

    首先我们来讲一下C# Linq中的Sum()方法。Sum()方法是用来计算序列中所有数值的和的方法,它可以用于数字类型(包括int、long、float、double等)或者是支持数值运算(例如加法)的自定义类型,但不包括bool类型。下面讲解一下具体用法和示例: 基本语法 序列.Sum([selector]) 其中,selector可以是一个Lambda表…

    C# 2023年4月19日
    00
  • C#中for循环、while循环循环执行的方法

    C#中的for循环和while循环是常用的循环结构,用于重复执行相同或类似的代码块,下面是它们的详细讲解和示例说明: for循环 for循环是一种经典的循环语句,用于重复执行一段代码,可以控制循环变量的初始值、终止条件和每次循环变量的增量。for循环的语法如下: for (初始化表达式; 循环条件; 迭代语句) { // 循环体语句 } 其中,初始化表达式只…

    C# 2023年6月7日
    00
  • 深入解析C#中的abstract抽象类

    深入解析C#中的abstract抽象类 介绍 在C#中,抽象类是一种不能直接实例化的类,它通常用于定义一个接口,强制子类实现一些方法。抽象类中至少有一个抽象方法,这些方法没有实现,只有定义。在子类中,这些抽象方法必须被实现才能使用。抽象类是OOP中的核心概念之一,深入理解抽象类对于程序员来说至关重要。 创建抽象类 在C#中,通过使用abstract关键字来定…

    C# 2023年6月1日
    00
合作推广
合作推广
分享本页
返回顶部