网络编程基础OK

上传人:da****ge 文档编号:243136824 上传时间:2024-09-16 格式:PPT 页数:227 大小:1.60MB
返回 下载 相关 举报
网络编程基础OK_第1页
第1页 / 共227页
网络编程基础OK_第2页
第2页 / 共227页
网络编程基础OK_第3页
第3页 / 共227页
点击查看更多>>
资源描述
网络编程技术,设计、讲授,:,谭献海,Email,:,xhtan,第一部分,网络编程基础,本章内容简介,Windows,编程基础,网络操作系统(,NOS,),相关概念,OS API,及应用,字节顺序,多进程与多线程,应用程序与底层硬件之间,的接口,1. Windows,编程基础,NOS,2.,网络操作系统相关概念,操作系统(,OS,),是,最靠近硬件的低层软件,。,操作系统是指负责控制和管理计算机硬件和软件资源、合理地组织计算机工作流程并方便用户使用的程序集合,它是计算机和用户之间的接口。,基本功能,Hardware,BIOS,OS,Applications,Computer system,操作系统的基本功能:,文件管理,设备管理,进程管理,存储管理,作业管理,用户接口,操作系统,网络操作系统,(NOS),网络操作系统(,NOS,)是网络用户和计算机网络的接口,它除了提供标准,OS,的功能外,还,管理计算机网络相关的硬件和软件资源,,诸如网卡、网络打印机、网络存储等,为用户提供文件共享、打印共享等各种网络服务以及电子邮件、,WWW,等专项服务。,NOS,主要的服务包括:,文件服务,把文件系统从单机扩展到网络(,FTP,);,打印服务,把本地打印扩展到网络打印;,目录服务,把网络资源以目录形式提供给用户;,通信服务,用户之间的消息传输;,安全管理,管理用户的权限和资源的访问权限,;,其它各种,通信或增值服务,(web,mail,proxy,等,),。,网络操作系统,目前主流的几种主要网络操作系统是:,Windows,操作系统:Microsoft公司的Windows系列,如Microsoft的NT ,Windows 2000 Advanced Server等。,UNIX,或,Linux,。其中,UNIX操作系统主要有SUN公司的Solaris,IBM公司的AIX等。Linux操作系统主要有Redhat,红旗Linux等。,Novell公司的Novell网(NetWare),Santa Cruz Operation,公司(,SCO,)的,UnixWare,3.,操作系统,API,函数(,WIN32 API,)及应用,Windows API,函数,WIN32 API,是,Microsoft Windows 32,位操作系统平台,的应用程序编程接口。,WIN32 API,函数是构筑,Windows,应用框架的基石,在它的下面是,Windows,的操作系统核心,上面是所有的,Windows,应用程序,如下图所示,有,控件,和,类库,两种实现方式。,Windows API,函数,Windows API,函数,分为,12,类:,窗口,函数、,绘图,函数、,位图与图标,函数、,文本和字体,函数、,设备描述表,函数、,菜单,函数、,文件处理,函数、,Windows,消息,函数、,硬件与系统服务,函数、,打印,函数、,网络,函数、,进程与线程,函数。,由于函数非常多,直接使用这些函数是比较复杂的。目前常用的可视化编程环境(如,VB,、,VC+,、,DELPHI,等)中提供了大量的,类库,和各种,控件,,它们对,OS API,进行了封装。,当然,如果要开发出更灵活、更实用、更具效率的应用程序,必然要涉及到直接使用,API,函数。虽然类库和控件使应用程序的开发简单得多,但它们只提供,Windows,的一般功能,对于比较复杂和特殊的功能来说,使用类库和控件是难以实现的,这时就需要采用,API,函数来实现。,Windows API,函数大全,网络,函数,消息,函数,文件处理,函数,打印,函数,文本和字体,函数,菜单,函数,位图、图标和光栅运算,函数,绘图,函数,设备场景,函数,硬件与系统,函数,进程和线程,函数,控件与消息,函数,Windows API,函数,附录,-windows API函数大全及其应用.doc,Windows API函数大全,Windows API函数应用实例-利用Windows API函数和注册表获取系统信息 (Delphi 程序实例),VB中调用Windows API函数检测当前系统环境 (VB 程序实例),实用的windows API函数,参考文献,郭立山.,Windows API函数实用手册,. 冶金工业出版社, 2003-08-01,姚巍.,Windows API函数在Visual Basic中的应用实例,. 人民邮电出版社, 2003-12-1,思考题,了解,VB, Delphi,提供的相关,OS API,控件或类库及其使用方法,Byte order,Little Endian,the low-order byte of the number is stored in memory at the lowest address, and the high-order byte at the highest address. (The little end comes first.),Intel processors,(those used in PCs),Big Endian,the high-order byte of the number is stored in memory at the lowest address, and the low-order byte at the highest address. (The big end comes first.),Motorola,processors,(those used in Macs) ;,network,transport,data,4 bytes Long Integer:,0x99887766,Byte3 Byte2 Byte1 Byte0,99 88 77 66,Big Endian,Base Address+0 Byte3,99,Base Address+1 Byte2,88,Base Address+2 Byte1,77,Base Address+3 Byte0,66,Little,Endian,Base Address+0 Byte0,66,Base Address+1 Byte1,77,Base Address+2 Byte2,88,Base Address+3 Byte3,99,Example,计算机采用,Little,或,Big,Endian,,一般的,Intel PC,采用,Little,Endian,网络通信采用,Big,Endian,channel.sin_addr.s_addr,=,htonl(INADDR_ANY,);,channel.sin_port,=,htons(SERVER_PORT,);,Utility routines,Convert between network byte order and the local hosts byte order,htons (host to network short),ntohs (network to host short),htonl (host to network long),ntohl (network to host long),字节顺序转换程序示例,sock =,socket,(AF_INET, SOCK_DGRAM, 0);,if(sock,= 0),printf(Socket,open errorn);,exit(1);,/* Construct local address structure*/,memset(&echoServAddr, 0,sizeof(echoServAddr,);,/* Zero out structure */,echoServAddr.sin_family,= AF_INET;,/* Internet address family */,echoServAddr.sin_addr.s_addr,=,htonl,(INADDR_ANY,);,echoServAddr.sin_port,=,htons,(uint16_t),echoServPort,);,/* Local port */,/* Bind to the local address */,int,error_test,=,bind,(sock, (,struct,sockaddr,*) &,echoServAddr,sizeof(echoServAddr,);,if(error_test, 0),printf(Binding,errorn);,exit(1);,5.,进程和线程,19,技术背景,在程序设计中,很多时候需要同时对,多个任务,加以控制,如在基于网络的可视电话系统开发中,要同时进行,语音采集,、,语音编,/,解码,、,图象采集,、,图象编,/,解码,、,语音和图象码流的传输,, 所有的这些事情都要,并行处理,。特别是语音信号,如果进行图象编解码时间过长,语音信号得不到服务,通话就会间断;如果图象或语音处理时间过长,而不能及时地传输码流数据,通信同样也会中断。,这就要求我们实现一种并行编程机制,最开始的时候,那些拥有机器低级知识的程序员编写一些“,中断服务程序,”,主进程的暂停是通过硬件级的中断实现的。尽管这是一种有用的方法,但对编程人员要求较高,程序可移植性差。,目前,:,多进程,/,多线程,进程和线程都是操作系统的重要概念,操作系统的重要概念:进程,什么是进程?,Unix,下的多进程编程,进程控制,信号处理,进程间通信,执行,就绪,等待,PCB,CPU,挂起,程序,-,进程,程序,是为完成特定任务,用某种语言编写的,一组指令的集合。指一段静态的代码。,进程,是程序的一次执行过程,是系统进行调,度和资源分配的一个独立单位。,什么是进程?,几个定义:,APUE: An executing instance of a program is called a process.,不准确,:程序一次运行可以创建多个进程,实质上根本不对,:在,Unix,下程序的运行并不产生一个新进程(见后面的,system(),等介绍),本课程的定义:进程是具有,独立地址空间,的程序运行单位,“,独立地址空间,”很重要,Unix,使用,flat address,,以,32,位系统为例,地址范围从,0x0-0xffffffff,。任何地址都是,虚拟地址,,要通过,页面映射,才能得到,物理地址,,这个过程对进程来说是透明的,进程看到的都是虚拟地址。,“,独立地址空间,”是指各个进程都有自己的虚拟地址空间(在,Linux,下为,0x0-0xbfffffff,),而且任何进程都只能访问到自己的虚拟地址空间。,5.1 Unix,下的多进程编程,1,、进程控制,2,、信号处理,3,、进程间通信(,IPC),5.1.1,进程控制,创建进程,:,fork,函数原型:,#include ,pid_t fork(void);,其中,,pid_t,是一个,unisigned int,,是进程号对应的数据类型,进程创建,fork,是,UNIX,最精美的语句,“,fork”,的意思就是一分为二,让当前进程复制出一个新的进程。当前的进程就是新进程的,父进程,,新进程称为,子进程,。,fork,把子进程,ID,返回给父进程,,,把,0,返回给子进程,,,通过对返回值的检查就可知道当前是父进程还是子进程,。,#include ,#include ,#include ,int,main(void,),pid_t,pid,;,if (,pid,=,fork,() 0) /,父进程返回,printf(“I,am the parent, my,pid,= %u, my childs,pid,= %,un,”,getpid,(),pid,);,else if (,pid,= 0) /,子进程返回,printf(“I,am the child, my,pid,= %u, my parents,pid,= %,un,”,getpid,(),getppid,();,else,perror(“fork,”);,return 1;,return 0;,进程创建,一般结构:,if (pid = fork() 0),parents code;,else if (pid = 0),childs code;,else,error handling;,父进程打开的文件描述字将被子进程继承。,获得当前进程,id,: getpid,获得父进程,id,: getppid,函数原型:,#include ,pid_t getpid(void);,pid_t getppid(void);,进程控制,执行一个新程序,exec,(),功能,:,执行一个文件,语法,:#include int,execl,(path,arg0,.,argn,(char*)0) char*path,*arg0,.,*argn; int,execv,(path,argv) char*path,*argv; int,execle,(path,arg0,.,argn,(char*)0,envp) char*path,*arg0,.,*argn,*envp; int,execve,(path,argv,envp) char*path,*argv,*envp; int,execvp,(file,argv) char*file,*argv;,说明,:,这是一个系统调用族,用于将,一个新的程序调入本进程所占的内存,并覆盖之,产生新的内存进程映象,。新的程序可以是可执行文件或,SHELL,批命令。,执行一个新程序,C,程序被执行时的调用形式,: main(intargc,char*argv,char*envp);,其中,,argc,是,参数个数,;,argv,是,参数字符串指针数组,;,envp ,是新进程的,环境变量,字符串的指针数组。,argc,至少为,1,argv0,为程序文件名,类似地,在上面的,exec,系统调用族中,,path,为新进程文件的,路径名, file,为新进程,文件名,若,file,不是全路径名,系统调用会按,PATH,环境变量,自动,找对应的可执行文件运行。若新进程文件不是一个可执行的目标文件,(,如批处理文件,),,则,execlp(),和,execvp(),会将该文件内容作为一个命令解释器的标准输入形成,system(),。,arg0,.,等指针指向,0,结束的字符串,组成新进程的有效,参数,且该参数列表以一个空指针结束。,arg0,至少必须存在并指向新进程文件名或路径名。,同样,argv,是字符串指针数组,argv0,指向新进程,文件名或路径名,并以一空指针结束。,envp,是一个字符串指针数组,以空指针结束,这些字符串组成新进程的,环境,.,system,(),功能:,产生一个新的进程, 在子进程中执行指定的命令,。,语法:#include ,#include ,int system(string),char *string;,说明:本调用将参数string传递给一个命令解释器(一般为sh)执行, 即string被解释为一条命令, 由sh执行该命令。若参数string为一个空指针则为检查命令解释器是否存在。,返回值:当参数为空指针时, 只有当命令解释器有效时返回值为非零。若参数不为空指针, 返回值为该命令的返回状态(同waitpid()的返回值) ; 命令无效或语法错误则返回非零值,所执行的命令被终止。,例子,:,char command81,;,int i,;,for (i=1;i 0:,等待进程,id,为,pid,的子进程。,pid = 0:,等待与自己同组的任意子进程。,pid = -1:,等待任意一个子进程,pid 0),设置信号动作系统调用,设置定时器,alarm,,函数原型:,#include ,unsigned int alarm(unsigned int seconds);,在,seconds,秒后向本进程发送一个,SIGALRM,信号。一般情况下返回,0,;如果已经有一个定时器被设置且还没有到时间,则返回上一个定时器剩余的时间。,#include ,#include ,static int,flag = 0,;,static void,sig_alrm,(int signo) ,flag = 1,;,int main(void) ,if (,signal,(SIGALRM, sig_alrm) = SIG_ERR) ,perror(“signal”);,exit(1);,alarm,(10);,pause,();,if (flag),printf(“SIGALRM receivedn”);,return 0;,设置信号动作系统调用,暂停,/,睡眠,pause,,,sleep,#include ,int pause(void);,int sleep(unsigned int seconds);,sleep,让进程睡眠,seconds,秒,,pause,让进程永远睡眠。如果在睡眠过程中被信号打断,它们将返回,-1,。,信号编程,功能更强的改变信号动作函数:,sigaction,。,解决早期,signal,函数的不可靠问题,int sigaction(int sig, const struct sigaction,*act, struct sigaction *oact);,信号的发送,发送信号函数,:,kill,与,raise,。,函数原型:,#include ,int,kill,(pid_t pid, int sig);,int,raise,(int sig);,信号的发送,kill,给进程号为,pid,的进程发送一个,sig,信号,pid 0,:发送给进程,ID,为,pid,的进程,pid = 0,:发送给与自己同组,并且自己有权限向其发送的进程,pid -1,:发送给进程组,ID,为,-pid,的进程,并且自己有权限向其发送的进程,pid = -1,:所有自己有权限向其发送信号的进程,raise,调用给自己发送一个,sig,信号,。,因此,,raise(sig);,等价于,kill(getpid(), sig);,IPC,: InterProcess Communication,UNIX,操作系统提供诸多进程间通信的方式,常见的有,管道通信,FIFO(,命名管道,),通信,共享内存,(shared memory),进程间通信(,IPC,),管道通信,最古老的,Unix IPC,工具,一个进程从管道一头写数据,另一个进程从管道另一头读数据。通信方式是单向的。,创建管道:,pipe,函数原型:,#include ,int fdes2;,int pipe(int fdes);,pipe,函数成功后,内核打开两个文件描述字,fdes0,和,fdes1,fdes1,为,输入,端,只能用于,写,;,fdes0,为,输出,端,只能用于,读,。,一般文件的,I/O,函数都可以用于管道,如,read,、,write,、,close,等等。,read(fd0,buf,size),Pipe(),fd1,写端,fd0,读端,write(fd1,buf,size),int,main(void,) ,pid_t,pid,;,int,fdes2;,if (,pipe,(fdes,) 0) ,perror(“pipe,”); exit(1); ,if (,pid,=,fork,() 0) /,父进程,写,close(,fdes,0);,write(,fdes,1, “Pipe test”, 9);,/*,往管道中写入 *,/,else /,子进程,读,char buf4096;,ssize_t,n;,close(,fdes,1),n =,read,(,fdes,0,buf, 4096); /*,从管道中读数据 *,/,if (n = 0) ,bufn, = 0;,printf(“%sn,”,buf,); ,return 0;,管道通信实例,当进程调用了,pipe,后,fork,被调用后,管道破裂,如果一个管道的读端已经关闭,进程还继续向写端写数据,如:,pipe(fdes);,close(fdes0); /,关闭读端,write(fdes1, “Let me die”, 10);,则进程会收到一个,SIGPIPE,信号,表示管道破裂。默认动作为结束进程。,读一个写端已经关闭的管道则,read,返回,0,。,管道的局限性,只支持单向数据流;,只能用于具有亲缘关系的进程之间通信;,没有名字;,管道的缓冲区是有限的(管道存在于内存中,在管道创建时,为缓冲区分配一个页面大小);,管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等;,FIFO,通信,FIFO,是一种特殊设备文件,又称为命名管道,(Named Pipe),。操作方法与普通文件类似。,对于普通文件,我们可以从文件任一位置读数据,也可以从任一位置写数据;数据读完不会消失。但对,FIFO,来说,我们只能从,文件头读数据,,从,文件尾写数据,。数据被某进程读走之后就会,消失,。,命名管道,命名管道是一个有名字,、,单向或双向的通信管道。对于同一主机来讲允许有多个同一命名管道的实例并且可以由不同的进程打开,但是不同的管道都有属于自己的管道缓冲区而且有自己的,通信,环境,互不影响,命名管道可以支持多个客户端连接一个服务器端。,命名管道客户端不但可以与本机上的服务器,通信,,也可以同其他主机上的服务器,通信,。,命名管道连接通信序列图,命名管道,Sever,和,Client,间通信的实现流程如下,命名管道,命名管道,Sever,和,Client,间通信的实现流程如下(流程图如上所示),:,1) Server,通过函数,CreateNamedPipe,创建一个新的命名管道的实例,并返回用于今后操作的句柄,或为己存在的管道创建新的实例。,2) Client,通过函数,WaitNamedPipe,使,Server,的进程等待来自,Client,的实例连接。,3) Server,端侦听来自,Client,端的连接请求,在超时值变为零以前,通过函数,ConnectNamedPipe,与命名管道建立连接,4) Client,端通过函数,CreateFile/CallNamedPipe,呼叫对,Server,端的连接,返回一个指向管道文件的句柄,与命名管道建立连接。,命名管道,5),双方通过管道,利用,WriteFile,ReadFile,传递信息,进行通信。,6) Server,可通过函数,DisConnectNamedPipe,单方面终止连接,停止通信,并可通过函数,ConnectNamedPipe,与命名管道再次建立连接,以便复用管道,并可使用同一管道与其它,Client,通信。,7) Client,端只能通过函数,CloseHandle,关闭管道,(Server,端亦可使用该函数,),。,进程间通信(,IPC,),Win32,进程间通信的方式主要有:,(,1,)剪贴板,(Clip Board),;,(,2,)动态数据交换,(DDE: Dynamic Data Exchange),;,(,3,)部件对象模型,(COM: Component Object Model),;,(,4,)文件映射,(File Mapping),;,(,5,)邮槽,(Mail Slots),;,(,6,)管道,(Pipes),;,(,7,),Win32,套接字,(Socket),;,(,8,)远程过程调用,(Remote Procedure Call: RPC),;,(,9,),WM_COPYDATA,消息,(WM_COPYDATA Message),。,自学,5.2,线程,Topics,线程的基本概念,线程控制,线程同步与通信,JAVA,多线程类简介,多线程应用实例,(2,个,),程序,:静态的计算机语言编写的代码。,进程,:进程(,Process,)是具有,独立地址空间,的,程序运行单位,。程序只是一组指令的有序集合,它本身没有任何运行的含义,只是一个,静态实体,。而进程则不同,它是程序在某个数据集上的执行,是一个,动态实体,:它因创建而,产生,,因调度而,运行,,因等待资源或事件而被处于,等待,状态,因完成任务而被,撤消,。,线程,:线程(,Thread,)是,进程,的,一个实体,,是比进程更小一级的执行单元,是,CPU,调度和分派的基本单位。一个进程在其执行过程中,可以产生多个线程,形成多条执行线索。,多线程的基本概念,多线程的基本概念,线程和进程的关系,是:线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。,线程可与属于同一进程的其它线程共享进程所拥有的全部资源,但是其本身基本上不拥有系统资源,只拥有一点点在运行中必不可少的信息,(,如程序计数器、一组寄存器和栈,),。,多进程,:操作系统中多个程序同时执行。,多线程,:程序中多个片断同时执行。,图示,:,线程和进程,单,进程、单线程,如:,MS-DOS,多,进程、单线程,如:,UNIX,单,进程、多线程,如:,Java,,,VxWorks,多,进程、每个进程多个线程,如:,Windows2000,、,Solaris,、,Mach,和,OS/2,线程和进程的区别,子线程与父线程运行在同一进程空间内,而子进程和父进程则运行在不同的空间。这样,同一进程内的不同线程间可以直接通过内存交换数据(但出于数据同步原因最好不要这样做)。,每个进程都有独立的代码和数据空间(进程上下文),进程切换的开销大。,线程:线程创建、销毁和切换的负荷远小于进程,又称为,轻量级进程,(,lightweight process,)。,在Win32的定义中一个进程至少拥有一个线程,所以进程也被叫做主线程。,文件,输入输出装置,各种系统资源,数据区段,程序区段,只有一个地方在执行,文件,输入输出装置,各种系统资源,数据区段,程序区段,同时有数个地方在执行,传统的进程,多线程的任务,线程和进程,多线程的优势,(,1,)在进程内创建、终止线程比创建、终止进程要快;,(,2,)同一进程内的线程间切换比进程间的切换要快,尤其是,用户级线程间的切换。,(,3,)并发程序的并发执行,在多处理器环境下更为有效。一,个并发程序可以建立一个进程,而这个并发程序中的若,干并发程序段可以分别建立若干个线程,使这些线程在,不同的处理机上,(,4,)每个进程具有独立的地址空间,而该进程内的所有线程,共享该地址空间。这样可以解决父子进程模型中,子进,程必须复制父进程地址空间的问题。,(,5,)线程对解决客户,/,服务器模型非常有效。,5.2.2,线程的生命周期及控制,线程是程序内部的一个顺序控制流,它具有一个特定的生命周期。,在一个线程的生命周期中,它总处于某一种状态中。,线程的状态表示了线程正在进行的活动以及在这段时间内线程能完成的任务。,线程的生命周期,创建,start,就绪,stop,结束,suspend,挂起,wait,等待,睡眠时间结束,resume,Notify,notifyAll,I/O,请求结束,I/O,请求,阻塞,分配时间片,运行,时间片结束,sleep,睡眠,线程的生命周期及控制,Win32,提供了一系列的,OS API,函数,(,线程类函数,),来完成线程的,创建,、,挂起,、,恢复,、,终结,以及,通信,等工作。,下面介绍其中的一些重要函数。,1.,线程函数,在启动一个线程之前,必须为线程编写一个全局的,线程函数,,这个线程函数接受一个,32,位的,LPVOID,作为参数,返回一个,UINT,,线程函数的结构为:,UINT,ThreadFunction(LPVOID,pParam,) /,线程处理代码,return0; ,在线程处理代码部分通常包括一个死循环,该循环中先等待某事情的发生,再处理相关的工作:,while(1) ,WaitForSingleObject,(,);/,或,WaitForMultipleObjects,(),/Do something ,线程控制,线程控制,一般来说,,C+,的,类成员函数,不能作为线程函数。这是因为在类中定义的成员函数,编译器会给其加上,this,指针。,如果一定要以类成员函数作为线程函数,通常有如下解决方案:,(,1,)将该成员函数声明为,static,类型,去掉,this,指针;,(,2,)不定义类成员函数为线程函数,而将线程函数定义为类的友元(,friend,)函数。这样,线程函数也可以有类成员函数同等的权限;,(,3,)可以对非静态成员函数实现回调,并访问非静态成员,此法涉及到一些高级技巧。,(详细介绍请参考,Word,文档讲义),线程及控制,2.,创建线程,进程的,主线程,由操作系统自动生成,,Win32,提供了,CreateThread,API,来完成,用户线程,的创建,该,API,的原型为:,HANDLE,CreateThread,(,LPSECURITY_ATTRIBUTES,lpThreadAttributes,/Pointer to a SECURITY_ATTRIBUTES structure,SIZE_T,dwStackSize,/Initial size of the stack, in bytes.,LPTHREAD_START_ROUTINE,lpStartAddress,/start address of the new thread,LPVOID,lpParameter,/Pointer to a variable to be passed to the thread,DWORD,dwCreationFlags,/Flags that control the creation of the thread,,缺省为,NULL,LPDWORD,lpThreadId,/Pointer to a variable that receives the thread identifier,返回线程标识,);,该函数在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄,其中各参数说明如下:,lpThreadAttributes,:指向一个,SECURITY_ATTRIBUTES,结构的指针,该结构决定了线程的安全属性,一般置为,NULL,;,dwStackSize,:指定了线程的堆栈深度,一般设置为,0,;,lpStartAddress,:表示新线程开始执行代码所在函数的地址,即线程的起始地址。一般情况为,(,LPTHREAD_START_ROUTINE)ThreadFunc,,其中,ThreadFunc,是线程函数名;,lpParameter,:指定了线程执行时传送给线程函数的参数;,dwCreationFlags,:控制线程创建的附加标志,可以取两种值。如果该参数为,0,,线程在被创建后就会立即开始执行;如果该参数为,CREATE_SUSPENDED,,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数,ResumeThread,被调用;,lpThreadId,:该参数返回所创建线程的,ID,;,如果创建成功则返回线程的句柄,否则返回,NULL,。,创建线程,CreateThread(),的功能,创建新线程,新线程默认处于就绪状态。除非在,dwCreationFlags,中进行了特定的设置,如,CREATE_SUSPENDED,,新线程将处于挂起状态,必须设置的参数主要是,lpStartAddress,、,lpParameter,、,lpThreadId,例如:,DWORD WINAPI Thread1(LPVOID param);,HANDLE hThread;,hThread=CreateThread(NULL,0,Thread1,hDCT,NULL,例,:,多线程在,TCPServer,程序中的使用,DWORD WINAPI Thread(LPVOID param);,/,线程函数,HANDLE hThread;,/,线程句柄,DWORD ThreadID;,/,用于取得线程标识, ,/sClient,来自哪里?,sClient,=,accept,(sListen,(SOCKADDR*), ,/,创建新线程,以,sClient,为线程的参数,hThread =,CreateThread,(NULL,0,Thread,(LPVOID),sClient,NULL,if (hThread = NULL),/,若线程创建失败,显示原因,printf(%sn,GetLastError();,例,:,多线程在,TCPServer,程序中的使用,DWORD WINAPI,Thread,(LPVOID param),char Text256;,/,定义接收缓冲区,int nRecv =,recv,(SOCKET)param, Text, strlen(Text), 0);,if(nRecv 0),TextnRecv = 0;,printf(,接收到数据:,%s n, Text);,/,关闭与客户端的连接,closesocket,(SOCKET)param);,return 1;,如果使用,C/C+,语言编写多线程应用程序,不能使用,win32,操作系统提供的,CreateThread,API,,而应该使用,C/C+,运行时库中的,_,beginthread,(或,_,beginthreadex,),,其函数原型为:,线程控制,uintptr_t,_,beginthread,(,void( _,cdecl,*,start_address,)( void * ),/Start address of routine that begins execution of new thread,unsigned,stack_size,/Stack size for new thread or 0,.,void *,arglist,/Argument list to be passed to new thread or NULL,);,uintptr_t,_,beginthreadex,(,void *security,/Pointer to a SECURITY_ATTRIBUTES structure,unsigned,stack_size,unsigned ( _,stdcall,*,start_address,)( void * ),void *,arglist,unsigned,initflag,/Initial state of new thread (0 for running or CREATE_SUSPENDED for suspended);,unsigned *,thrdaddr,);,线程控制,3.,终止线程,线程的终止有如下四种方式:(,1,),线程函数正常返回,;(,2,)线程自身,调用,ExitThread,函数终止自己,其原型为:,VOID,ExitThread(UINT,fuExitCode,);,它将参数,fuExitCode,设置为线程的退出码。注意:如果使用,C/C+,编写代码,应该使用,C/C+,运行时库函数,_,endthread,(_,endthreadex,),来终止线程,决不能使用,ExitThread,!,线程控制,(,3,)同一进程或其它进程的线程调用,TerminateThread,函数来终止线程,其原型为:,BOOL,TerminateThread(HANDLE,hThread,DWORD,dwExitCode,);,该函数用来结束由,hThread,参数指定的线程,并把,dwExitCode,设成该线程的退出码。当某个线程不再响应时,我们可以通过其它线程调用该函数来终止这个不响应的线程。,(,4,)包含线程的进程终止,建议:最好使用第,1,种方式终止线程,4.,挂起与恢复线程,当我们创建线程的时候,如果给其传入,CREATE_SUSPENDED,标志,则该线程创建后被挂起,我们应使用,ResumeThread,恢复它:,DWORD,ResumeThread,(HANDLE,hThread,);,如果,ResumeThread,函数运行成功,它将返回线程的前一个暂停计数,否则返回,0x FFFFFFFF,。对于没有被挂起的线程,程序员可以调用,SuspendThread,函数强行挂起之:,DWORD,SuspendThread,(HANDLE,hThread,);,一个线程可以被挂起多次。线程可以自行暂停运行,但是不能自行恢复运行。如果一个线程被挂起,n,次,则该线程也必须被恢复,n,次才可能得以执行。,线程控制,线程控制,5.,设置线程优先级,当一个线程被首次创建时,它的优先级等同于它所属进程的优先级。在单个进程内可以通过调用,SetThreadPriority,函数改变线程的相对优先级(相对于其所属进程)。,BOOL SetThreadPriority(HANDLE hThread, int nPriority);,其中参数,hThread,是指向待修改优先级线程的句柄,线程与包含它的进程的优先级关系如下:,线程优先级,=,进程,类基本优先级,+,线程,相对优先级,进程类,的基本优先级包括:,(,1,),实时,:,REALTIME_PRIORITY_CLASS,;,(,2,),高,:,HIGH _PRIORITY_CLASS,;,(,3,),高于正常,:,ABOVE_NORMAL_PRIORITY_CLASS,;,(,4,),正常,:,NORMAL _PRIORITY_CLASS,;,(,5,),低于正常,:,BELOW_ NORMAL _PRIORITY_CLASS,;,(,6,),空闲,:,IDLE_PRIORITY_CLASS,。,线程控制,从,Win32,任务管理器中可以直观地看到这六个进程类优先级,如下图:,线程的,相对优先级,包括:,(,1,),空闲,:,THREAD_PRIORITY_IDLE,;,(,2,),最低,线程:,THREAD_PRIORITY_LOWEST,;,(,3,),低于正常,线程:,THREAD_PRIORITY_BELOW_NORMAL,;,(,4,),正常,线程:,THREAD_PRIORITY_ NORMAL,(,缺省,),;,(,5,),高于正常,线程:,THREAD_PRIORITY_ABOVE_NORMAL,;,(,6,),最高,线程:,THREAD_PRIORITY_HIGHEST,;,(,7,),关键时间,:,THREAD_PRIOTITY_CRITICAL,。,线程控制,线程控制,6.,睡眠,VOID,Sleep,(DWORD dwMilliseconds);,该函数可使线程暂停自己的运行,直到,dwMilliseconds,毫秒过去为止。,线程控制,7.,其它重要线程,API,获得线程优先级,一个线程被创建时,就会有一个默认的优先级,但是有时要动态地改变一个线程的优先级,有时需获得一个线程的优先级。,Int,GetThreadPriority,(HAND
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 小学资料


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!