网络:端口、进程与线程

Reading time ~1 minute

端口

概念:

端口包括物理端口和逻辑端口。物理端口是用于连接物理设备之间的接口,逻辑端口是逻辑上用于区分服务的端口。TCP/IP协议中的端口就是逻辑端口。一个IP地址的端口通过16bit进行编号,最多可以有65536个端口。范围是从0 到65535。

端口有什么用呢?一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等,这些服务都可以通过一个IP地址来实现,那如何区分不同的服务呢,这时就要通过“IP地址+端口号”来区 分不同的服务。

可以这样理解: 知乎shotgun的答案:网络地址是家庭住址,端口是门牌号码,网络数据包是快递,快递员(网络驱动)根据不同的门牌号(端口)把包裹(数据包)送到不同的人家(应用或服务)。

理论上只有服务器软件才会绑定固定端口,客户端的一般是随机的。客户端端口和服务端端口是独立的。就像你和你朋友的门牌号不同,却可以互相通信(只要在通信时互相知道对方的网络地址和端口)。

使用:

TCP与UDP段结构中端口0-65535范围,对于这65536个端口号有以下的使用规定:

  1. 端口号小于256的定义为常用端口,服务器一般都是通过常用端口号来识别的。任何TCP/IP实现所提供的服务都用1—1023之间的端口号,是由ICANN来管理的;
  2. 客户端只需保证该端口号在本机上是惟一的就可以了,使用过后释放供其它服务使用。客户端口号因存在时间很短暂又称临时端口号;
  3. 大多数TCP/IP实现给临时端口号分配1024—5000之间的端口号。大于5000的端口号是为其他服务器预留的。

进程

进程是正在运行的程序的实例。是一个具有独立功能的程序关于某个数据集合的一次运行活动。它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体。 ps:进程和线程关系推荐这篇:进程与线程的一个简单解释

线程

概念:

通常在一个进程中可以包含若干个独立的执行流,即线程。它们可以利用进程所拥有的资源。 每个线程都是作为利用CPU的基本单位,是花费最小开销的实体。 在一个进程中的多个线程之间,可以并发执行。同样,不同进程中的线程也能并发执行。

对于C#,任何C#程序都有一个默认的线程,即主线程。一个线程要么是前台线程,要么是后台线程。后台线程与前台线程类似,区别是后台线程不会影响进程终止。当属于进程的前台线程全部终止后,不管后台线程是否结束,进程都结束。 如果使用一个线程监视某些服务(如套接字连接),可以将其设置IsBackground设为True,以便该线程不会影响进程终止。

终止线程的方法:

  1. 事先设置一个控制变量,在其他线程修改它来表示是否终止线程。在该线程中检测控制变量,以确定是否退出线程。这是比较好的方法。
  2. 调用Thread中的Abort方法,强行终止线程。使用Abort方法时线程实际不一定会立刻终止。因为结束线程前需要进行代码清理等工作,但我们并不知道这会消耗多久时间,因此可能出现类似死机的现象。为避免这个问题,可在主线程中调用子线程的Join方法,并指定主线程等待子线程结束的等待时间。

暂停线程:

Thread.Sleep(1000); 暂停该语句所在线程1000毫秒。

合并线程:

Join方法用于把指定线程合并到当前线程中。如果一个线程T1执行过程中需要等待另一个线程T2结束才能继续执行,可以在T1中调用T2.Join();

Volatile关键字:

volatile修饰符表示所声明字段可以被多个并发执行的线程修改。读取这个变量的值时候每次都是从momery里面读取而不是从cache读。编译器将不再对该字段优化,可以保证该字段在任何时间呈现的都是最新的值。

线程优先级:

在C#中线程有5个优先级,由高到低是: AboveNormal、BelowNormal、Highest、Lowest、Normal。 创建时如果不指定则默认是Normal。

线程同步:

多线程解决了吞吐量和响应速度的问题,但也带来了资源共享问题,如死锁和资源争夺。 同步是多线程中一个非常重要的概念。所谓同步,是指多个线程之间在后行顺关联关系。如果一个线程必须在另一个线程完成某个工作后才能继续执行,则必须考虑如何让其保持同步,以确保在系统上同时运行多个线程而不会出现死锁或逻辑错。

lock语句:

C#提供了一个lock语句。lock关键字能确保当一个线程位于代码的临界区(可以理解为一段代码)时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码段,则它将一直等待(即被阻塞),直到锁定的对象被释放以后才能进入临界区。 lock关键字将代码段(语句块)标记为临界区,它的实现原理是首先锁定某一个私有对象,然后执行代码段中的语句,当代码段中的语句执行完毕后,再解除该锁。

线程池:

线程池是在后台执行多个任务的线程集合。 线程池不会占用主线程,也不会延迟后续请求的处理。一旦池中的某个线程用完规定的时间段,它将返回到等待线程队列中,等待被再次使用。这种重用使应用程序可以避免为每个任务创建新线程引起的资源和时间消耗。线程池有一个最大线程数限制。如果所有线程都繁忙,则额外的任务将放入队列中,直到有线程可用时才能够得到处理。一旦一项工作任务被加入到线程池的队列中,就不能取消该任务,直到该任务完成。

注意,托管线程池中的线程为后台线程,即它们的IsBackground为True。意味着所有前台线程退出后,ThreadPool也会退出。

进程与端口

从本质上看,进程和端口毫无关系。 端口是为了区分同一IP地址的主机中的服务而出现的,就相当于电话的分机号码一样。进程是为了管理一个程序中的线程才引入的概念。两个之间没有必然的联系。 端口是为了进行通信,虚拟出的一种概念;而进程,相当于一种执行体,加载了数据、执行代码等等。

只是,现在很多的东西依赖于网络,因此,基于网络服务的程序会需要打开端口监听,这个时候,进程打开一个端口,外部网络客户端访问这个端口,两者就可以建立起连接进行通信。 一个进程绑定了一个端口比如10000,另一个进程就无法再绑定这个端口了。 一个进程和一个端口并不完全是一对一的关系。因为一个进程是可以绑定多个端口的。

Scriptable Objects 及 游戏架构

Scriptable Objects 相关介绍,及基于其的游戏架构技术 Continue reading

AssetBundle 最佳实践

Published on January 29, 2019

AssetBundle 基础总结

Published on January 27, 2019