第20章 网络编程技术--笔记

124 阅读7分钟

第20章 网络编程技术--笔记


内容来自c#从入门到精通 .Net API broswer

什么是网络?

各个孤立的工作站或主机相连在一起,从而达到资源共享和通信的目的。

计算机网络技术实现了多个计算机系统互联,相互连接的计算机之间彼此能够进行数据交流


1.局域网和广域网

计算机网络分为局域网(local area network LAN)和广域网(wide area network WAN)。

局域网是指在某一个区域内由多台电脑通过一定形式连接在一起的计算机组,可以由两台电脑组成,也可以由同一区域内上千台电脑组成。

由局域网延伸到更大的范围的网络称为广域网,因特网(internet)就是广域网。

2.网络协议

网络协议规定了计算机之间连接的物理、机械、电气等特征,以及计算机之间的相互寻址特征、数据发送冲突的解决方案、长数据分段传送与接受规则等。就像不同的国家有不同的法律一样,网络协议也有多种。

IP

因特网采用的协议是TCP/IP。依靠它,因特网可在全球范围内实现不同硬件结构、不同操作系统、不同网络系统的互联。因特网上存在数以亿计的主机,每台主机在网络上,通过分配的因特网地址表示自己,地址就是IP地址。

到目前为止,IP地址用4个字节,32位二进制数来表示,称为IPv4。为便于使用,取用每个字节的十进制表示,每个字节用.隔开,如 192.168.1.1。现在正在试验使用16个字节(128位)表示IP地址,IPv6。

IP地址相当于每台电脑在网络中的一个身份证ID,是唯一的

TCP

网络协议中,有两个高级协议,分别为传输控制协议TCP,用户数据报协议UDP。

TCP是一种以固接连线为基础的协议,可提供两台计算机间可靠的数据传送。TCP可以保证从一端数据传送至连接的另一端时,数据能确实送到,而且送到数据的排列顺序和送出时的顺序相同。TCP适合可靠性要求比较高的场合,像接打电话一样。

UDP

UDP是无连接通信协议,不可靠的数据传输,能向若干个目标发送数据,接收发自若干个源的数据。UDP以独立发送数据包的方式进行。像广播一样。

3.端口与套接字

端口

设备与外界通讯交流的一个出口,所有的数据都通过这个出口与其他计算机或设备相连。网络程序设计中的端口(port)并非真实的物理存在,而是一个假象的连接装置。端口被规定为一个在0 ~ 65535的整数,0 ~ 1023的端口号通常用于一些比较知名的网络服务和应用,编写程序应该使用1024以上的端口号。

套接字

叫做Socket,英文原意插座,在网络程序中socket用于将程序与网络连接起来,说白了就是给程序设计的一个插座,程序想要连接网络不是那么简单的,想要接收或发送网络数据,需要处理繁琐的网络协议,以及复杂的数据格式,甚至考虑的本地硬件的因素。

每访问一次网络,就需要处理这些东西一次,程序员可能要疯了。于是有了套接字,它相当于一个门面,把复杂的操作隐藏(封装)在了套接字的后面,对于程序员来说,只需要调用套接字中的方法,剩下的连接数据分析,全都让套接字自己去做。

所以说,程序就像一盏电灯,插上套接字提供的插座,就通电了,灯就会亮起来。

image.png

4.IP地址封装

C#中有3个与IP地址相关的类,分别是Dns类,IPAddress,IPHostEntry类,都位于System.Net命名空间中

Dns类是一个静态类,它从因特网域名系统(DNS)检索关于特定主机的信息。

IPHostEntry类的实例中返回来自DNS查询的主机信息。如果指定的主机在DNS中有多个入口,则IPHostEntry包含多个IP地址和别名。

Dns类 提供简单的域名解析功能。

public static IPAddress[] GetHostAddresses (string hostNameOrAddress);
返回指定主机的 Internet 协议 (IP) 地址。
参数:要解析的主机名或 IP 地址。
返回:一个 IPAddress 类型的数组,用于保存由 hostNameOrAddress 参数指定的主机的 IP 地址。 
public static IPHostEntry GetHostEntry (string hostNameOrAddress);
将 IP 地址解析为 IPHostEntry 实例。
参数:IP 地址
返回:一个 IPHostEntry 实例,包含有关 address 中指定的主机的地址信息    

IPAddress 类 提供 IP地址。

public bool IsIPv6SiteLocal { get; }
了解地址是否为 IPv6 站点本地地址。
如果 IP 地址为 IPv6 站点本地地址,则为 true;否则为 false。    

IPHostEntry 类 为主机地址信息提供容器类

public string HostName { get; set; } 获取或设置主机的 DNS 名称   包含服务器的主要主机名的字符串 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;//1.需要用到IP地址封装的类,添加命名空间
//访问同一局域网中的主机名称
namespace Demo04
{
    
    class Program
    {
        static void Main(string[] args)
        {
            string ip, name, localip = "127.0.0.1";
            string localname = Dns.GetHostName(); //获取本地计算机的主机名
            IPAddress[] ips = Dns.GetHostAddresses(localname);//返回指定主机的 Internet 协议 (IP) 地址。
            foreach (IPAddress ip1 in ips) 
            {
                if(!ip1.IsIPv6SiteLocal) //判断地址是否为 IPv6 地址。
                {//如果不是ipv6地址
                    localip = ip1.ToString();//获取本机IP地址
                    
                }
            }
            Console.WriteLine($"本机名:{localname} 本机IP地址:{localip}");
            //遍历本地局域网中的地址192.168.1.50 至 192.168.1.60
            for (int i = 50; i <= 60; i++)
            {
                ip = "192.168.1." + i;//生成ip字符串
                try
                {
                    IPHostEntry host = Dns.GetHostEntry(ip);//获取ip封装对象
                    name = host.HostName;//获取指定ip地址的主机名
                    Console.WriteLine($"本机名:{name} 本机IP地址:{ip}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("没有该主机");
                }
                
            }
        } 
    }
}
​

5.TCP程序设计

TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。在C#中,TCP程序设计是指用Socket类、TcpClient类、TcpListener类编写的网络通信程序,这3个类都位于System.Net.Sockets命名空间中。TCP进行通信的两个应用程序是有主次之分的,一个称为服务器端程序,另一个称为客户端程序。

image.png

Socket

Socket类为网络通信提供了一套丰富的方法和属性,主要用于管理连接,实现Berkeley通信端套接字接口,同时还定义了绑定、连接网络端点、传输数据所需的各种方法,提供处理端点连接传输等细节所需要的功能。

TcpClient和UDPClient 等类在内部使用Socket类,

TcpClient类用于在同步阻止模式下通过网络来连接、发送、接受流数据。

为了使TcpClient连接并交换数据,TcpListener实例或Socket实例必须侦听是否有传入的连接请求

可以通过以下两种方式之一连接到此侦听器:

  • 创建一个TcpClient,并调用Connect()方法连接
  • 使用远程主机的主机名和端口号创建 TcpClient 。 此构造函数将自动尝试连接。

TcpListener类用于在阻止同步模式下侦听和接受传入的连接请求。

image.png

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace Server
{
    /// <summary>
    /// 创建服务器端项目Server
    /// 在Main()创建TCP连接对象
    /// 然后监听客户端接入,并读取接入的客户端IP地址和传入的消息
    /// 最后向客户端发送一条消息
    /// </summary> 
    internal class Program
    {
        static void Main(string[] args)
        {
            int port = 888; //端口
            TcpClient tcpClient; //创建TCP连接对象
            IPAddress[] serverIP = Dns.GetHostAddresses("127.0.0.1");//定义Ip地址
            IPAddress localAddress = serverIP[0];//IP地址
            TcpListener tcpListener = new TcpListener(localAddress, port);//监听套接字
            tcpListener.Start();//开始监听传入的连接请求
            Console.WriteLine("服务器启动成功,等待用户接入...");
            //在死循环中监听是否有客户端接入,
            //如果有客户端接入
            while (true) 
            {
                try
                {
                    tcpClient = tcpListener.AcceptTcpClient();//每接受一个客户端则生成一个TcpClient
                    NetworkStream networkStream = tcpClient.GetStream();//获取网络数据流
                    BinaryReader reader = new BinaryReader(networkStream);//定义流数据读取对象
                    BinaryWriter writer = new BinaryWriter(networkStream);//定义流数据写入对象

                    while (true)
                    {
                        try
                        {
                            string strReader= reader.ReadString();//接收信息
                            string[] strReaders = strReader.Split(new char[] {' '});//截取客户端信息
                            Console.WriteLine("有客户端接入,客户IP:"+ strReaders[0]);//输出接收的客户端IP地址
                            Console.WriteLine("来自客户端的信息:" + strReaders[1]);//输出接收的信息
                            string strWriter = "我是服务器,欢迎光临";//定义服务端要写入的消息
                            writer.Write(strWriter);//向对方发送信息
                        }
                        catch
                        {
                            break;
                        }
                    }

                }
                catch
                {
                    break;
                }
            }       
        }
    }
}