操作系统课程设计论文.docx
《操作系统课程设计论文.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计论文.docx(26页珍藏版)》请在冰豆网上搜索。
操作系统课程设计论文
学号100510119
操作系统课程设计论文
题目多线程管理与线程通信
学院四川大学锦江学院
专业计算机科学与技术
学生姓名钟霖
导师姓名李炳法
内容摘要
随着科学技术的发展,通信变得越来越重要,如何实现不同主机之间的通信,成为越来越多人关心的问题。
本次课程通过实现两个端口,一个服务端口,通过多线程为客户端提供了一个交流的平台。
客户通过客户端建立用户,进行信息交流。
1、理解线程
要讲解线程,不得不说一下进程,进程是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它系统资源组成。
进程在运行时创建的资源随着进程的终止而死亡。
线程的基本思想很简单,它是一个独立的执行流,是进程内部的一个独立的执行单元,相当于一个子程序,它对应于VisualC++中的CwinThread类对象。
单独一个执行程序运行时,缺省地包含的一个主线程,主线程以函数地址的形式出现,提供程序的启动点,如main()或WinMain()函数等。
当主线程终止时,进程也随之终止。
根据实际需要,应用程序可以分解成许多独立执行的线程,每个线程并行的运行在同一进程中。
一个进程中的所有线程都在该进程的虚拟地址空间中,使用该进程的全局变量和系统资源。
操作系统给每个线程分配不同的CPU时间片,在某一个时刻,CPU只执行一个时间片内的线程,多个时间片中的相应线程在CPU内轮流执行,由于每个时间片时间很短,所以对用户来说,仿佛各个线程在计算机中是并行处理的。
操作系统是根据线程的优先级来安排CPU的时间,优先级高的线程优先运行,优先级低的线程则继续等待。
线程被分为两种:
用户界面线程和工作线程(又称为后台线程)。
用户界面线程通常用来处理用户的输入并响应各种事件和消息,其实,应用程序的主执行线程CWinAPP对象就是一个用户界面线程,当应用程序启动时自动创建和启动,同样它的终止也意味着该程序的结束,进程终止。
工作线程用来执行程序的后台处理任务,比如计算、调度、对串口的读写操作等,它和用户界面线程的区别是它不用从CWinThread类派生来创建,对它来说最重要的是如何实现工作线程任务的运行控制函数。
工作线程和用户界面线程启动时要调用同一个函数的不同版本;最后需要读者明白的是,一个进程中的所有线程共享它们父进程的变量,但同时每个线程可以拥有自己的变量。
2、线程的管理和操作
(一)线程的启动
创建一个用户界面线程,首先要从类CwinThread产生一个派生类,同时必须使用DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE来声明和实现这个CwinThread派生类。
第二步是根据需要重载该派生类的一些成员函数如:
ExitInstance()、InitInstance()、OnIdle()、PreTranslateMessage()等函数。
最后调用AfxBeginThread()函数的一个版本:
CWinThread*AfxBeginThread(CRuntimeClass*pThreadClass,intnPriority=THREAD_PRIORITY_NORMAL,UINTnStackSize=0,DWORDdwCreateFlags=0,LPSECURITY_ATTRIBUTESlpSecurityAttrs=NULL)启动该用户界面线程,其中第一个参数为指向定义的用户界面线程类指针变量,第二个参数为线程的优先级,第三个参数为线程所对应的堆栈大小,第四个参数为线程创建时的附加标志,缺省为正常状态,如为CREATE_SUSPENDED则线程启动后为挂起状态。
对于工作线程来说,启动一个线程,首先需要编写一个希望与应用程序的其余部分并行运行的函数如Fun1(),接着定义一个指向CwinThread对象的指针变量*pThread,调用AfxBeginThread(Fun1,param,priority)函数,返回值赋给pThread变量的同时一并启动该线程来执行上面的Fun1()函数,其中Fun1是线程要运行的函数的名字,也既是上面所说的控制函数的名字,param是准备传送给线程函数Fun1的任意32位值,priority则是定义该线程的优先级别,它是预定义的常数,读者可参考MSDN。
(二)线程的优先级
以下的CwinThread类的成员函数用于线程优先级的操作:
intGetThreadPriority();
BOOLSetThradPriority()(intnPriority);
上述的二个函数分别用来获取和设置线程的优先级,这里的优先级,是相对于该线程所处的优先权层次而言的,处于同一优先权层次的线程,优先级高的线程先运行;处于不同优先权层次上的线程,谁的优先权层次高,谁先运行。
至于优先级设置所需的常数,自己参考MSDN就可以了,要注意的是要想设置线程的优先级,这个线程在创建时必须具有THREAD_SET_INFORMATION访问权限。
对于线程的优先权层次的设置,CwinThread类没有提供相应的函数,但是可以通过Win32SDK函数GetPriorityClass()和SetPriorityClass()来实现。
(三)线程的悬挂和恢复
CWinThread类中包含了应用程序悬挂和恢复它所创建的线程的函数,其中SuspendThread()用来悬挂线程,暂停线程的执行;ResumeThread()用来恢复线程的执行。
如果你对一个线程连续若干次执行SuspendThread(),则需要连续执行相应次的ResumeThread()来恢复线程的运行。
(四)结束线程
终止线程有三种途径,线程可以在自身内部调用AfxEndThread()来终止自身的运行;可以在线程的外部调用BOOLTerminateThread(HANDLEhThread,DWORDdwExitCode)来强行终止一个线程的运行,然后调用CloseHandle()函数释放线程所占用的堆栈;第三种方法是改变全局变量,使线程的执行函数返回,则该线程终止
关键词:
多线程通信服务端口客户端
目录
1.课程设计1
1.1功能主要设计内容1
1.2主要设计原理1
2.课程设计需求分析2
3.概要设计2
3.1整体设计框架2
3.2各模块的基本算法2
3.2.1多线程原理2
4.系统实现3
4.1原理3
4.2运行环境Eclipse简介3
4.3流程图描述5
4.3代码描述10
4.3.1服务端代码10
4.3.2客户端代码14
5.系统测试17
5.1系统功能测试17
6.总结22
参考文献24
1.课程设计
1.1功能主要设计内容
本设计主要采用java语言编写,设计一个模拟的多线程通信,可以实现客户端通过服务端,实现客户端与客户端之间进行通信。
主要分为两部分,一部分为SeriverSocket端和ClientSocket端。
1.2主要设计原理
线程是进程中能够执行的实体,是进程的组成部分,也是处理器调度和分派的基本单位。
允许进程包含多个可并发的线程,这些线程共享进程所获得的主存空间和资源,可以完成某一项任务而协同工作。
在java语言中,多线程的机制是通过虚拟CPU来实现的。
可以形象的理解为,在一个java程序内部虚拟了多台计算机,每台计算机对应一个线程,有自己的CPU,可以获取所需要的代码和数据,因此能独立执行任务,相互间还可以共用代码和数据。
Java的线程是通过java.lang.Thread类来实现的,它内部实现了虚拟CPU的功能,能够接收和处理传递给它的代码数据,并提供了独立的运行控制功能。
每个线程都是某个特定Thread对象所对应的run()方法来完成其操作的,方法run()称为线程体。
在计算机网络技术中,两个进程间可以通过一个双向的网络通信连接实现数据交换,这种通信链路的端点被称为“套接字”,套接字在具体实现中又分为服务套接字和客户端套字。
客户端有两种,通常用来实现“客户—服务器”连接和数据传输。
当进程间通过网络进行通信时,java技术仍使用它的流模型。
每个Socket对象都封装了相应的一个输入流和一个输出流对象。
如果一个进程要通过网络向另一个进程发送数据,只需简单地将数据写到与其Socket相关联的输出流中去,相对应的,一个进程可以从相关联的输入流来读取另一个进程所写出的数据。
建立网络连接之后,使用与Socket相关联的I/O流一旦打开,其使用方式和先前其它I/O流的使用方式完全相同。
两台计算机之间如果要建立网络连接,一台机器中必须运行一个进程来等待连接,而另一台机器必须试图连接到前一台机器。
这和电话系统类似,必须由一方发起呼叫,而此时另一方必须处于等待呼叫状态。
所不同的时,Socket通信的两端不是对等的—等待连接请求的一端称为服务器,而主动发起连接的一端称为客户机。
建立连接时所需的寻址信息包括:
远程计算机的机器名或IP地址;试图连接的对方端口号。
2.课程设计需求分析
随着网络的快速发展,人与人之间的交越来越多,如何让双方或者是更多人同时进行通信已经变得越来越重要。
在当今信息世界里,聊天工具的使用是非常频繁的,如MSN、QQ、校内通,之类的聊天工具许多人都正在使用。
此次课程设计通过多线程通信,主要采用了建立客户端与用户端之间进行通信,虽然其功能简单,但基本实现了多个用户同时进行通信。
3.概要设计
3.1整体设计框架
本程序主要分为两部分,一部分为TestServer端(服务端),主要用于监听通信端口,接收客户端连接请求,每当有新用户上线时会进行如下处理:
1.打开与该用户相关联的I/O流
2.接收新用户名
3.将新用户信息(包括用户名和对应的输出流对象)加入到在线用户列表中去
4.启动一个新的线程,该线程负责监听并转发此新用户的发言信息
另一部分为TestClient端(客户端),主要是用于创建Socket对象,连接服务器的9999端口,建立连接后,通过创建新进程进行多个用户之间的通信。
其主要是包括以下几个主要方面:
1.创建界面
2.输入用户的名字
3.建立连接
4.创建进程,实现进程之间的通信
3.2各模块的基本算法
3.2.1多线程原理
每个正在系统上运行的程序都是一个进程。
每个进程包含一到多个线程。
进程也可能是整个程序或者是部分程序的动态执行。
线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。
也可以把它理解为代码运行的上下文。
所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。
通常由操作系统负责多个线程的调度和执行。
线程是程序中一个单一的顺序控制流程.在单个程序中同时运行多个线程完成不同的工作,称为多线程.线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文.多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定.线程的运行中需要使用计算机的内存资源和CPU。
一个采用了多线程技术的应用程序可以更好地利用系统资源。
其主要优势在于充分利用了CPU的空闲时间片,可以用尽可能少的时间来对用户的要求做出响应,使得进程的整体运行效率得到较大提高,同时增强了应用程序的灵活性。
更为重要的是,由于同一进程的所有线程是共享同一内存,所以不需要特殊的数据传送机制,不需要建立共享存储区或共享文件,从而使得不同任务之间的协调操作与运行、数据的交互、资源的分配等问题更加易于解决。
4.系统实现
4.1原理
通过Socket建立连接,以ChatServer作为服务器,作为一个中间平台进行进行交流,然后通过ChatClient作为客户端,建立多个用户,分别输入用户名登陆,输入交流的信息。
当用户要通信时,只需在其它写入要的内容,通过DataOutputStream(s.getOutputStream())将其写进去。
通过线程自动的将其写入到服务端的内容显示到各个用户去。
里面主要是用到了Hashtable,它的作用是实现一个哈希表,该哈希表将键映射到相应的值,显示相应的信息来自哪个用户,方法put()将指定key映射到此哈希表中的指定value,通过名字对应相应的消息。
Remove(Objectkey)从哈希表中移除该键及其相应的值。
如果该键不在哈希表中,则此方法不执行任何操作。
4.2运行环境Eclipse简介
Eclipse是著名的跨平台的自由集成开发环境(IDE)。
最初主要用来Java语言开发,但是目前亦有人通过插件使其作为其他计算机语言比如C++和Python的开发工具。
Eclipse的本身只是一个框架平台,但是众多插件的支持使得Eclipse拥有其他功能相对固定的IDE软件很难具有的灵活性。
许多软件开发商以Eclipse为框架开发自己的IDE。
Eclipse是一个开放源代码的软件开发项目,专注于为高度集成的工具开发提供一个全功能的、具有商业品质的工业平台。
它主要由Eclipse项目、Eclipse工具项目和Eclipse技术项目三个项目组成,具体包括四个部分组成——EclipsePlatform、JDT、CDT和PDE.JDT支持Java开发、CDT支持C开发、PDE用来支持插件开发,EclipsePlatform则是一个开放的可扩展IDE,提供了一个通用的开发平台。
它提供建造块和构造并运行集成软件开发工具的基础。
EclipsePlatform允许工具建造者独立开发与他人工具无缝集成的工具从而无须分辨一个工具功能在哪里结束,而另一个工具功能在哪里开始。
EclipseSDK(软件开发者包)是EclipsePlatform、JDT和PDE所生产的组件合并,它们可以一次下载。
这些部分在一起提供了一个具有丰富特性的开发环境,允许开发者有效地建造可以无缝集成到EclipsePlatform中的工具。
EclipseSDK由Eclipse项目生产的工具和来自其它开放源代码的第三方软件组合而成。
Eclipse项目生产的软件以CPL发布,第三方组件有各自自身的许可协议.
4.3流程图描述
图1ChatServer服务器流程图
图2ChatServer服务器流程图
图3窗口器流程图
图4线程运行流程表
图5Socke通信模型
4.3代码描述
4.3.1服务端代码
importjava.io.*;
import.*;
importjava.awt.*;
importjava.awt.event.*;
publicclassChatClient{
privateStringname;
privateSockets;
privateDataInputStreamdis;
privateDataOutputStreamdos;
privateFramef;
privateTextAreata;
privateTextFieldtf;
privatebooleanrunnable=true;
publicstaticvoidmain(Stringargs[]){
ChatClientcc=newChatClient();
cc.createUI();
cc.inputName();
cc.connect();
cc.createThread();
}
publicvoidcreateUI(){
f=newFrame("Client");
ta=newTextArea();
tf=newTextField();
Buttonsend=newButton("Send");
Panelp=newPanel();
p.setLayout(newBorderLayout());
p.add(tf,"Center");
p.add(send,"East");
f.add(ta,"Center");
f.add(p,"South");
MyClientListenerlistener=newMyClientListener(this);
send.addActionListener(listener);
tf.addActionListener(listener);
f.addWindowListener(newWindowAdapter(){
publicvoidwindowClosing(WindowEvente){
ChatClient.this.shutDown();
}
});
f.setSize(400,400);
f.setLocation(600,0);
f.setVisible(true);
}
publicvoidinputName(){
Stringname=javax.swing.JOptionPane.showInputDialog("InputYourName:
");
this.setName(name);
f.setTitle(name);
}
publicvoidconnect(){
try{
s=newSocket("127.0.0.1",9999);
dos=newDataOutputStream(s.getOutputStream());
dis=newDataInputStream(s.getInputStream());
dos.writeUTF(name);
}catch(IOExceptione){
e.printStackTrace();
}
}
publicvoidcreateThread(){
MyClientReaderreader=newMyClientReader(this);
reader.start();
}
publicvoidstop(){
runnable=false;
}
publicvoidshutDown(){
try{
dos.writeUTF("再见");
ta.append("Exitin5seconds!
");
this.stop();
Thread.sleep(1000);
dis.close();
dos.close();
s.close();
}catch(Exceptione){
}
System.exit(0);
}
publicbooleangetRunnable(){
returnrunnable;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicDataInputStreamgetDataInputStream(){
returndis;
}
publicDataOutputStreamgetDataOutputStream(){
returndos;
}
publicTextAreagetTextArea(){
returnta;
}
publicTextFieldgetTextField(){
returntf;
}
}
classMyClientListenerimplementsActionListener{
privateChatClientclient;
publicMyClientListener(ChatClientclient){
this.client=client;
}
publicvoidactionPerformed(ActionEvente){
TextFieldtf=client.getTextField();
Stringinfo=tf.getText();
try{
client.getDataOutputStream().writeUTF(info);
}catch(IOExceptione1){
e1.printStackTrace();
}
if(info.equals("bye")){
client.shutDown();
}
tf.setText("");
}
}
classMyClientReaderextendsThread{
privateChatClientclient;
publicMyClientReader(ChatClientclient){
this.client=client;
}
publicvoidrun(){
Stringinfo;
DataInputStreamdis=client.getDataInputStream();
TextAreata=client.getTextArea();
try{
while(client.getRunnable()){
info=dis.readUTF();
ta.append(info+"\n");
}
}catch(IOExceptione){
}
}
}
4.3.2客户端代码
importjava.io.*;
import.*;
importjava.util.*;
publicclassChatServer{
publicstaticvoidmain(Stringargs[]){
HashtableuserList=newHashtable();
Stringname;
DataInputStreamdis;
DataOutputStreamdos;
try{
ServerSocketss=newServerSocket(9999);
while(true){
Sockets=ss.accept();
dis=newDataInputStream(s.getInputStream());
dos=newDataOutputStream(s.getOutputStream());
name=dis.readUTF();
userList.put(name,dos);
newMyServerReader(name,dis,userList).sta