分散式:
各自独立的计算机系统之间没有资源或信息的交换或共享
存在大量的数据冗余及数据不一致性,维护成本高,已被淘汰
集中式:
数据的存储和处理都在单个计算机系统上,用户终端只有显示器和键盘
优点是硬件成本低,无数据冗余和数据不一致性
缺点是可靠性低,访问速度受同时使用的用户数量影响,且无法满足特殊部门的数据要求
分布式:
分散式和集中式的混合体,把分散的资源以一个整体的形式呈现给用户,是目前比较完善的方案
数据冗余低,访问速度快
C/S结构的开发和维护成本比B/S高:采用C/S时对于不同客户端要开发不同的程序,且软件的安装、调试和升级都需要在所有客户机上进行
C/S的客户端不仅负责与用户交互、收集用户信息,而且还需要完成通过网络向服务器请求对数据库、电子表格或文档等信息的处理工作,而B/S的客户端把事务处理逻辑部分交给服务器而客户端只需显示
C/S相对于B/S安全性高,C/S可以通过严格的管理派发软件,达到保证系统安全的目的
C/S是一种胖客户端应用程序编程架构,其主要工作都在客户端运行,优点是可以充分利用本地计算机的性能优势,缺点是需要在本机安装客户端软件
B/S使用HTTP进行通信。优点是单台计算机可以访问任何Web服务器,缺点是B/S模式有沙盒限制
套接字是一种通信机制,通信双方的一种约定,用套接字中的相关函数来完成通信过程
套接字是支持TCP/IP网络通信的基本操作单元,可以将套接字看作是不同主机间的进程进行通信的端点。在一个套接字实例中,既保存了本机的IP地址和端口,也保存了对方的IP地址和端口,同时也保存了双方通信采用的网络协议等信息
3种类型:
流式套接字:实现面向连接的TCP通信
数据报套接字:实现无连接的UDP通信
原始套接字:实现IP数据包通信
System.Net命名空间下
识别远程主机:主机标识+端口号
注:主机标识是“哪台” 端口号是“哪个进程”
解决多个进程同时进行通信的问题
端口地址范围:0~65535,1000以内的端口号大多呗协议占用
①IP地址字符串转换为IPAddress实例
IPAddress ip=IPAddress.Parse(“143.24.20.36”);
②判断IPv4/IPv6
if(ip.AddressFamily==AddressFamily.InterNetwork/InterNetworkV6)
IPAddress localAddress=IPAddress.Parse(“192.168.1.1”);
IPEndPoint iep=new IPEndPoint(localAddress,65000);
string s1=“IP地址为”+iep.Address;
string s2=“IP端口为”+iep.Port;
一般和Dns类一起使用
①获取搜狐服务器的所有IP地址
IPAddress[] ips=Dns.GetHostEntry(“news.sohu.com”).AddressList;
利用Dns类的GetHostEntry方法获取IPHostEntry实例
②获取本机所有的IPv4和IPv6地址
ips=Dns.GetHostEntry(Dns.getHostName()).AddressList;
域名地址(字符型)—>IP地址(数字型) 的过程就叫域名解析
IPAddress[] ips=Dns.GetHostAddresses(“www.cctv.com”);
IPAddress[] ips=Dns.GetHostAddresses("");
IPHostEntry host=Dns.GetHostEntry("");
var ipAddresses=host.AddressList;
string name=host.HostName;//获取本地主机名
string hostname=Dns.GetHostName();
(1)进程和线程有什么区别?为什么要使用多线程?多线程适用于哪种场合?
①进程是正在执行的程序,线程是某个进程中的一个或多个执行流
进程是资源调度和分配的基本单位,线程是CPU调度和分配的基本单位
线程是进程的组成部分,一个进程包含多个线程,一个线程必须有一个父线程
线程之间可以共享内存数据,进程之间不能共享内存数据
②多线程可以让多个任务同时执行
多线程可以提高资源利用效率,提高吞吐量,防止阻塞主线程
比方说多步骤任务处理,分割成多个线程去处理
③当执行需要较长时间时才能完成连续操作时,或者等待网络或者其他I/O设备响应时,都可以使用多线程技术
(2)前台线程和后台线程有什么区别和联系?如何判断一个线程属于前台线程还是后台线程?如何将与一个线程设置为后台线程?
①联系:一个线程要么是前台线程要么是后台线程
区别:后台线程不会影响进程的终止,而前台线程则会影响进程的终止
②用Thread对象创建的线程默认是前台线程,在托管线程池中执行的线程默认是后台线程
③从非托管代码进入托管执行环境的所有线程都会被自动标记为后台线程
①执行某语句时,在该语句完成之前不会执行其后面的代码,这种执行方式称为同步执行
②当并行执行的多个线程同时访问某些资源时,必须考虑如何让多个线程保持同步,同步的目的是为了防止多个线程同时访问某些资源时出现死锁和争用的情况
③C#提供的lock语句可以简单地实现代码同步
①线程池是在后台执行任务的线程集合
②好处有:如当某个线程无法进入线程池执行时先将其放入等待队列,自动决定用哪个处理器执行线程池中的某个线程,自动调节这些线程执行时的负载平衡问题等。另外,线程池总是在后台异步处理请求的任务而不会占用主线程,也不会延迟主线程中后续请求的处理
获取本机可用的逻辑内核数:
StringBuilder sb=new StringBuilder();
sb.AppendLine("本机处理器数:"+Environment.ProcessorCount);
sb.AppendLine("是否为64位操作系统:"+Environment.Is64BitOperatingSystem);
sb.AppendLine("当前进程是否为64位进程:"+Environment.Is64BitProcess);
sb.AppendLine("当前进程占用的物理内存量:{3:#.##}MB"+Environment.WorkingSet/1024.0/1024.0);
System.Diagnostics命名空间、操作系统级别
2种启动方法:
①
Process myProcess=new Process();
myProcess.StartInfo.FileName="Notepad.exe";//准备执行记事本
myProcess.StartInfo.Arguments="Test.txt";//创建或打开的文档为Test.txt
myProcess.StartInfo.WindowStyle=ProcessWindowStyle.Normal/Hidden/Minimized/Maximized;
myProcess.Start();
②
Process.Start(“Notepad”);
①Kill和CloseMainWindow方法
Kill:强行终止进程;终止没有图形化界面进程的唯一方法
CloseMainWindow:请求终止
②HasExited属性
1)判断进程是否已经关闭
if(!process.HasExited){
process.CloseMainWindow();
}
2)关闭本地计算机上当前运行的所有Notepad.exe实例:
Process[] myProcess=Process.GetProcessesByName("Notepad");
foreach(Process process in myProcess){
process.CloseMainWindow();
}
③WaitForInputIdle方法
仅适用于具有用户界面的进程;进入空闲状态,可用于等待信息输入
Process myProcess=Process.Start("Notepad");
myProcess.WaitForInputIdle();
④WaitForExit方法
⑤ExitCode属性和ExitTime属性
⑥EnableRaisingEvents属性
//获取本地所有进程
Process[] myProcesses1=Process.GetProcesses();
//获取远程计算机上指定名称的进程,参数可以是远程计算机名或IP地址
Process[] myProcesses2=Process.GetProcesses("192.168.1.0");
//获取本机指定名称的进程
Process[] myProcess1=Process.GetProcessesByName("MyExeFile");//不带扩展名
//获取远程计算机上指定名称的进程,参数1是进程名,参数2是远程计算机的名称或IP地址
Process[] myProcesses2=Process.GetProcessesByName("Notepad","Server1");
System.Threading;利用Thread或ThreadPool可在一个进程中实现多线程并行执行
IsBackground属性、IsThreadPoolThread属性
①创建两个线程
Thread t1=new Thread(Method1);
Thread t2=new Thread(Method2);
......
public void Method1(){...}
public void Method2(Object obj){...}
//与下列等价
//线程是通过委托来实现的
Thread t1=new Thread(new ThreadStart(Method1()));//定义的方法不带参数
Thread t2=new Thread(new ParameterizedThreadStart(Method2()));//带参数
...
public void Method1(){...}
public void Method2(Object obj){...}
②设置后台线程
Thread myThread=new Thread(Method1);
myThread.IsBackground=true;
t1.Start();//调用不带参数的方法
t2.Start(“MyString”);//调用带参数的方法
当将方法作为一个单独的线程执行时,如果方法带有参数,只能在启动线程时传递实参,而定义该方法的参数只能是一个Object类型,如果希望传递多个参数,可以先将这些参数封装到一个类中,然后传递该类的实例,再在线程中通过该类的实例访问响应的数据
2种方法
①public volatile bool shouldStop;
②取消线程的执行(非正常终止)≠销毁线程
t.Abort()
Thread.Sleep(1000);
赋予较高优先级:
Thread t1=new Thread(MethodName);//默认优先级为Normal
t1.Priority=ThreadPriority.AboveNormal;
当把某线程的优先级设置为最高时,在该线程结束前,其他所有线程都将无法获得执行的机会,这会导致界面看起来像死机一样,所以使用最高优先级时要特别消息
线程池是后台执行任务的线程集合,与Thread的主要区别是线程池中的线程是有关联的
①托管线程池中的线程都是后台线程
②添加到线程池中的任务不一定会立即执行。如果所有线程都繁忙,则新添加到线程池的任务将放入等待队列中,知道有现成可用时才能够得到处理
③线程池可自动重用已创建过的线程,一旦池中的某个线程完成任务,它将返回到等待线程队列中,等待被再次使用,而不是直接销毁它。这种重用技术使应用程序可避免为每个任务创建新线程引起的资源和时间消耗
④开发人员可设置线程池的最大线程数
⑤线程池中的线程都是利用多核处理技术来实现的
ThreadPool.QueueUserWorkItem(new WaitCallback(Method1()));
ThreadPool类只提供静态方法,不能创建实例
CPU在执行程序时有两种形式,一种是执行某语句时,在该语句完成之前不会执行其后面的语句,同步执行;另一种是执行某语句时,不管该语句是否完成,都会继续执行其后面的语句,异步执行
并行:同时执行
当并行执行的多个线程同时访问某些资源时,必须考虑如何让多个线程保持同步。或者说,同步的目的是为了防止多个线程同时访问某些资源时出现死锁和争用情况
死锁:
两个线程都停止响应,并且都在等待对方完成,从而导致任何一个线程都不能继续执行
争用:
多次运行同一个程序可能会产生不同的结果,而且每次运行的结果不可预知
当程序的结果取决于两个或多个线程中的哪一个先到达某一特定代码块时出现的一种错误
加锁或原子操作
①用volatile修饰符锁定公共或私有字段
private static volatile bool isStop=false;
public static bool IsStop{
get{return isStop;}
set{isStop=value;}
②用Interlocked类提供的静态方法锁定局部变量
通过加锁和解锁提供了原子级别的静态操作方法
int num=0;
Interlocked.Increment(ref num);//将num的值加1
Interlocked.Decrement(ref num);//将num的值减1
③用lock语句锁定代码块
private List<int> list=new List<int>();
...
lock(list){...}
private Object lockedObj=new Object();
...
lock(lockedObj){...}