用JAVA实现基于Socket的分布计算.doc_第1页
用JAVA实现基于Socket的分布计算.doc_第2页
用JAVA实现基于Socket的分布计算.doc_第3页
用JAVA实现基于Socket的分布计算.doc_第4页
用JAVA实现基于Socket的分布计算.doc_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

并行计算课程设计用JAVA实现基于Socket的分布计算求解N*N的矩阵乘法问题1 概述11 题目要求假设需求计算两个很大的矩阵之间的相乘,而且有多台计算机处于WAN中并使用TCP/IP进行通信。编写一个通过用分布式计算的方式来求解矩阵乘法问题。12 解决方法及结论题目要求使用一台计算机运行客户程序、几台计算机运行服务程序求解N*N矩阵得乘法问题,在这种分布模型下,一个并行应用很容易使用客户/服务模式来设计。运行客户程序的机器称为客户机,运行服务程序的计算机称为服务器。一个客户机可以将一个大的应用分成若干个小的问题,这些小的问题可以由多个服务器同时处理,所以服务器对应问题求得解后,再发送给客户机。客户机汇集所有从服务程序发来的结果,然后再输出给用户,这就实现了分布并行计算的过程。在具体实现该模型的过程中,需要将多个可用服务器和其Internet域名保存在一个文件中,该文件称为服务器配置文件,由客户程序存取它。客户程序同时还要读取另一个文件,称为客户配置文件。它包括用户定义的应用参数。这种用“管理者/工作者”模式实现的C/S结构如图1.1所示。图1.1用“管理者/工作者”模式实现的C/S结构完成这一分布计算的步骤可以这样来实现:首先,设置一个服务器来配置文件“srvcfg.txt”,客户程序通过这个文件获取了所有的服务器必要的信息,如服务器的个数、IP地址或主机名。然后,建立与所有服务的Socket连接和I/O流。客户程序从“clicfg.txt”文件获得矩阵维数N的值,再创建A、B、C三个矩阵,并输入矩阵A、B的值。接着在客户端对任务进行分解,并向每个工作者节点发送一个子任务,即矩阵A乘以矩阵B的一个子块。任务要求每个服务程序收到该请求后,完成计算并把结果返回客户。而客户等待服务的回答,并将计算结果拼接起来,组成矩阵C。最后,客户将得到的结果矩阵C返回给客户。2 问题和实现机制实现“客户/服务”模式有多种方式,在Java中可以使用远程调用(RMI)、Socket连接和Agent来实现,本程序使用Socket实现“客户/服务”模式。另外,在使用Socket实现“客户/服务”模式时要用到流、文件读写的类和多线程技术等。21 I/O流与SocketJava采用流的概念来传输数据。流式输入输出是一种很常见的输入输出方式,它是一阁比文件所包含的范围更广的概念。流是一个流动的数据序列。流可分为输入流和输出流。输入流将外部数据引入到计算机中,输入流通数据源相连,用来从数据源中读取数据。例如,从网络中读取信息、从扫描仪中读取图像信息等。输出流将数据引导到外部设备。例如,向网络中发送信息、在屏幕上显示图像和文件内容等。流的最大特点是数据的获取和发送均按照数据序列顺序进行:每一个数据都必须等待排在它面前的数据读入或送出之后才能被读写,而不能随意的选择输入输出的位置。磁带机是实现流式输入输出的较典型设备。可以将“流”看做是数据从一种设备流向另一种设备的过程,也可以看做是一个相连的字节块。从概念上讲,流的一端可以和数据源或数据接收器相连,另一端可以认为与java.io包中的类相连。Socket类用于网络上进行通信,这种通信往往要借助Java的I/O流。发送方的数据源和接收器都可以指网络的另一端,但要进行数据交换必须首先建立起某种连接,这种连接必须依靠Socket完成。在网络的两个节点之间利用Socket与ServerSocket建立连接。211 基本I/O流Java.io包提供了各种流类来处理输入输出。这些类能够非常灵活地向“规则的”文件中保存数据或从中读取数据,网络数据的传输也能够用这些概念来完成。流是java.io包中几乎所有类的基础,这个包有大量的类。InputStream类是以字节为单位的输入流。数据来源可以是键盘,也可以是诸如Internet这样的网络环境。该类可作为许多输入类的基类。InputStream是一个抽象类,因此不能建立它的实例,相反用户必须使用其子类。 OutputStream是与InputStream相对应的输出流类,它具有所有输出流的基本功能。通过DataOutputStream类向输出流中写入一个Java的基本数据类型,所写数据的方式是可移植的,即与具体操作系统无关。它们能用DataInputStream类读取。在使用这个类之前,必须创建一个OutputStream对象作为一个DataInputStream类的构造函数的输入参数。DataInputStream类以与机器无关的方式从一个输入流中读Java的基本数据类型,所读数据应是由DataInputStream对象所写入的。FileOutputStream类是从OutputStream类所派生出来的简单输出类,它可以简单地向文件中写入数据。我们能用FileOutputStream类创建一个输出流的实例来连接一个输出文件,并用它作为一个DataOutputStream对象的输入,这样就可以使用它提供的方法来输出各种类型的数据。FileInputStream类是从InputStream类中派生出来的简单输入流类,它可以处理简单的文件输入操作。212 Socket在Internet上有很多主机运行着多个服务软件,同时提供几种服务。每种服务打开一个Socket,并绑定到一个特定的端口上,不同的端口对应不同的服务。提供这些服务的服务软件,称之为服务程序,使用这些服务的服务软件称之为客户程序。Socket类用于网络上进程间的通信,可以用于实现客户Socket。通过调用Socket类的构造函数,就可以在特定的端口号创建一个与指定主机的连接。同时,还可以指明通信将基于一个面向连接的基于流的协议,如TCP/IP或者是一个无连接协议,如UDP。UDP是一个比较简单的传输协议,他不像TCP/IP那样能够保证传输的正确性。Socket类能够提供客户端的接口。ServerSocket类将服务器所监听的端口号传递给ServerSocket的构造函数,就可以创建一个ServerSocker,并把该连接绑定在这个特定的端口上。22 多线程多线程就是一个类或一个程序执行或管理多个线程或执行任务的能力。每个线程可以独立于其他线程而独立运行,如果需要的话,也可以和其他线程协同运行。一个类控着他的所有线程,可以决定哪个线程得到优先级、哪个线程可以访问其他类的资源、哪个线程开始执行、哪个保持休眠,等等。操作系统必须提供对线程的支持。在Java中可以继承Thread类或实现Runnable接口以实现多线程技术。在许多情况下,一个类已经扩展了Frame类或Applet类,因而这样的类就不能再继承Thread。Runnable接口为一个类提供了一种手段,无须扩展Thread类就可以执行一个新的线程或者被一个新的线程所控制。所有实现了Runnable接口的类的对象都可以用线程方式执行。这种使用Runnable接口构造线程的方法是要在一个类中实现public void run方法,并且建立一个Thread类型的域。当实例化一个线程时,该线程本身就会作为参数,将它的run()方法与Thread对象联系在一起,这样就可以用start()和sleep()方法来控制这个线程。使用Runnable接口,一个类可以避开单继承去扩展另一个类,此外还可以使用一个或多个线程。即使一个类不需要扩展其他的类,这时它可以扩展Thread类,但如果所有要做的事情就只是实现run()方法,也可能还是使用Runnable接口更为简单。23 系统详细设计整个程序由服务端和客户端两个部分组成,为了使程序结构更清晰,将主要功能实现和运行时状态显示的图形界面分别作为独立的类来实现,这是为了使整个程序运行过程中图形界面能够响应用户的操作。而且在功能实现部分使用了多线程技术,这是为了实现并行分布处理。 客户端和服务端交互过程客户端和服务端的交互过程如图2.1所示。在该交互过程中,服务端的基本步骤如下:(1) 在一个未使用的端口上创建一个Socket。(2) 等待在该端口上的连接,一旦获得客户程序的请求,立即接受该请求。(3) 为该Socket建立一个输入流和输出流,为客户程序和服务程序之间的通信奠定基础。(4) 把控制权交给ServerBody(),它包含并行应用的实现代码,ServerBody()应定义一个线程类的子类,这样服务程序可以接受客户的连接请求,创建Socket,然后调用ServerBody()的线程,处理客户程序的服务请求。(5) 送回处理结果,等待另一个客户连接。客户端程序的基本步骤如下:(1) 阅读服务器配置文件,以获得可用服务器的信息。(2) 创建一个Socket和输入/输出数据流数组对应于每个服务器,客户端对每个服务器要产生一个线程,使之能够与这些服务器建立连接。(3) 把控制权交给ClientBody(),它包含并行应用的特定代码,主要是把一个大的应用划分成若干部分,并把这些部分传送给各个服务程序,然后等待回送计算结果。最后将计算结果合并,求得原问题的解。(4) 关闭所有与服务程序相对应的流和Socket。图2.1 客户端和服务端的交互过程 客户程序框架客户端程序由两个类组成,FrmC类实现图形界面,显示运行时的状态;Netc类实现现客户端的主要功能,这是程序的核心部分。FrmC类实现的客户端的界面如图2.2所示。FrmC类的程序框架:public class FrmC extends JFrame implements ActionListener /成员变量,其中console用于显示程序运行时的状态/其他变量用于版面布局 public JTextArea console = new JTextArea(客户端运行状态信息.n); JPanel jPanel1 = new JPanel(); BorderLayout borderLayout1 = new BorderLayout(); JPanel jPanel2 = new JPanel(); JButton okButton = new JButton(); JScrollPane jScrollPane = new JScrollPane();public FrmC() /*实现版面布局,并进行初始化*/ public void actionPerformed(ActionEvent e) /* 创建Netc实例,并将console作为参数传入*/ public static void main(String args) 图2.2 客户端界面Netc类的程序框架:public class Netc implements Runnable static Socket sock; /定义一个socket数组。 static InetAddress Serveraddr; /定义一个数组用来存储所有servers的ip地址。 static DataInputStream datain; /定义一个输入流数组。 static DataOutputStream dataout; /定义一个输出流数组。 static int NumServers; /存储服务器的数目。 static JTextArea consoleOutput; /显示程序运行时的提示信息。 private Thread runner; /成员方法public void init() throws IOException /*进行初始化*/ /读取服务器配置文件srvcfg.txt /读出所有可用服务器的个数和它们的主机名或IP地址 /打开服务配置文件,实例化数组 /打开连接server的socket,并设置流 for(count = 0;countNumservers;count+) ServerAddrcount=InetAddress.getByname(Servernamecount); ServerSocketcount=new Socket(ServerAddrcount,8001); /调用ClientBody方法来解决问题 public static void ClientBody() throws IOException /* 读取配置文件clicfg.txt,然后对矩阵进行划分 * 并分别传给各个服务器端 * 最后,接收从各个服务器端传来的数据 * 并重新组合成计算结果矩阵 */ public void run() /*调用init()方法*/ public void start() /* 启动一个线程*/ public Netc(JTextArea console) /*初始化consoleOutput,然后调用start()方法*/ 服务程序框架服务端程序的大致结构和客户端程序有些相似,也是有两个类组成,FrmS类实现图形界面,显示运行时的状态;Nets类实现服务端的主要功能,这是程序的核心部分。服务端的界面如图2.3所示。图2.2 服务端界面FrmS类的程序框架:public class FrmS extends JFrame implements ActionListener /成员变量,其中console用于显示程序运行时的状态/其他变量用于版面布局 public JTextArea console = new JTextArea(服务端运行状态信息.n); JPanel jPanel1 = new JPanel(); BorderLayout borderLayout1 = new BorderLayout(); JPanel jPanel2 = new JPanel(); JButton listenPort = new JButton(); JScrollPane jScrollPane = new JScrollPane(); /成员方法 public FrmS () /* 实现版面布局,并进行初始化 */ public void actionPerformed(ActionEvent e) /* 创建Nets实例,并将console作为参数传入*/ public static void main(String args) Nets类的程序框架:public class Nets implements Runnable /定义所有用于Socket连接和I/O流的变量 static Socket mySocket; /定义一个连接客户端的socket。 static ServerSocket SS; /定义一个Server Socket。 static DataInputStream datain; /定义一个输入流。 static DataOutputStream dataout; /定义一个输出流。 static int MumServers; / static JTextArea consoleOutput; /显示程序运行时的提示信息。 private Thread runner;/成员方法public void init() throws IOException /*创建一个ServerSocket实例 *并调用start()方法启动一个线程开始监听1237端口 */ ServerSocket = new ServerSocket(1237); public static void ServerBody() throws IOException /*接收从客户端传来的矩阵,计算矩阵相乘的结果 *最后将结果返回客户端 */public void run() /*开始监听端口,等待客户端的连接 *若连接成功,则设置输入和输出流 *然后调用ServerBody()方法 */public void start() /* 启动一个线程 */ public Nets(JTextArea console) /*初始化 consoleOutput, 然后调用start ()方法 */ 3 程序功能演示在程序中实现了多台计算机分布计算N*N的矩阵。在客户程序中用到了两个文件一个“srvcfg.txt”,用来保存了服务器的个数及其相应的IP地址。在文件中存储格式如下:23228还有一个文件“clicfg.txt”,用来保存矩阵的维数N的值。 图3.1服务程序在第二台机器上执行的结果 图3.2服务程序在第一台机器上执行的结果在实验中比如有两台电脑做服务器,将它们的IP地址分别存入“srvcfg.txt”,假设客户端有一个N维的数组需要计算。把这两个配置文件和客户程序放在同一个目录下,然后再两台电脑上都执行服务器端程序,并启动端口监听,如图3.1、3.2所示,然后在其中的一台电脑上再启动客户端程序,执行结果如图3.3所示。图3.3 客户端程序执行的结果4 结论本程序成功的演示了使用Socket进行了一种分布式计算模式的尝试,可以在多台服务器并行独立去计算N阶矩阵的乘法。将计算结果返回给客户端。实现了并行计算过程。在实现过程中,为了使图形用户界面能够持续地响应用户的操作,将程序的主要功能一独立线程的方式实现。不过该程序也有一些不足,为了简化矩阵的分组,假设矩阵的维数能被服务端的数目整除,如果条件不满足,虽然程序能够运行,但是计算结果不正确。只能在客户端程序当中设置该矩阵。5 参考文献1 并行程序设计(美)Barry Wilkinson,Michael Allen著 陆鑫达等译 北京:机械工业出版社 20022 Java就业培训教程 张孝祥著 北京:清华大学出版社 20033 Java编程思想,(美)BruceEckel 著 陈昊鹏 饶若楠等译 北京:机械工业出版社 20064 Java项目设计与开发范例 朱福喜等著 北京:电子工业出版社 2006附录:程序源代码 客户端的实现代码FrmC类:import java.awt.*;import java.awt.event.*;import javax.swing.*;public class FrmC extends JFrame implements ActionListener public JTextArea console = new JTextArea(客户端运行状态信息.n); JPanel jPanel1 = new JPanel();BorderLayout borderLayout1 = new BorderLayout(); JPanel jPanel2 = new JPanel(); JButton okButton = new JButton();JScrollPane jScrollPane = new JScrollPane(); public FrmC() setSize(300, 400); setLocation(300, 200); jPanel1.setLayout(borderLayout1); this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setTitle(客户端); okButton.setText(开始计算); okButton.addActionListener(this); jPanel2.add(okButton, new FlowLayout(); jPanel1.add(jPanel2, BorderLayout.NORTH); jScrollPane.getViewport().add(console); jPanel1.add(jScrollPane, BorderLayout.CENTER); this.getContentPane().add(jPanel1, BorderLayout.CENTER); public void actionPerformed(ActionEvent e) new Netc(console); public static void main(String args) FrmC frmC = new FrmC(); frmC.show(); Netc类:import java.io.*;import .*;import javax.swing.*;public class Netc implements Runnable static Socket sock; /定义一个socket数组。 static InetAddress Serveraddr; /定义一个数组用来存储所有servers的ip地址。 static DataInputStream datain; /定义一个输入流数组。 static DataOutputStream dataout; /定义一个输出流数组。 static int NumServers; /存储服务器的数目。 static JTextArea consoleOutput; /显示程序运行时的提示信息。 private Thread runner; public void run() try init(); catch (IOException ex) consoleOutput.append(n 有IO异常抛出); public void start() runner = new Thread(this); runner.start(); public void init() throws IOException int i; DataInputStream ServerConfigFile; /*用来读取服务器配置文件srvcfg.txt*/ String IntString = null, Servernames; ServerConfigFile = new DataInputStream(new FileInputStream(srvcfg.txt); try IntString = ServerConfigFile.readLine(); catch (IOException ioe) consoleOutput.append(n Error reading the # servers); System.exit(1); try NumServers = Integer.parseInt(IntString); /把字符串转化为整数。 catch (NumberFormatException nfe) consoleOutput.append(n r servers is not an interger.); System.exit(1); /现在我们知道了服务器的数目,可以实例化数组了。 Servernames = new StringNumServers; sock = new SocketNumServers; Serveraddr = new InetAddressNumServers; datain = new DataInputStreamNumServers; dataout = new DataOutputStreamNumServers; for (i = 0; i NumServers; i+) try Servernamesi = ServerConfigFile.readLine(); catch (IOException e) consoleOutput.append(n Error reading server names); System.exit(1); Servernamesi = Servernamesi.trim(); try ServerConfigFile.close(); catch (IOException e) consoleOutput.append(n Error reading server names); System.exit(1); /打开对server的socket,并设置流。 try for (i = 0; i NumServers; i+) /得到IP地址。 Serveraddri = InetAddress.getByName(Servernamesi); socki = new Socket(Serveraddri, 1237); dataini = new DataInputStream( new BufferedInputStream(socki.getInputStream(); dataouti = new DataOutputStream( new BufferedOutputStream(socki.getOutputStream(); catch (IOException E) consoleOutput.append(n I/O Error openning stream sockets.); System.exit(1); /调用ClientBody过程来解决问题。 ClientBody(); try /关闭流和sockets。 for (i = 0; i NumServers; i+) dataouti.close(); dataini.close(); socki.close(); catch (IOException E) consoleOutput.append(n error closing streams and Sockets); System.exit(1); public static void ClientBody() throws IOException int i, j, k; int TotNum = 0; /矩阵(方阵)的维数。 int NumRows = 0; /根据服务器的数目,对矩阵划分后的每个矩阵的行数。 int A, B, C; DataInputStream ClientConfigFile; String IntString = null; ClientConfigFile = new DataInputStream(new FileInputStream(clicfg.txt); try IntString = ClientConfigFile.readLine(); catch (IOException ioe) consoleOutput.append(n error reading N from file.); System.exit(1); try TotNum = Integer.parseInt(IntString); /把字符串转换成整数。 catch (NumberFormatException nfe) consoleOutput.append(n the value for N is not an integer.); System.exit(1); try ClientConfigFile.close(); catch (IOException e) consoleOutput.append(n I/O error closing config file.); System.exit(1); NumRows = TotNum / NumServers; A = new intTotNumTotNum; B = new intTotNumTotNum; C = new intTotNumTotNum; for (i = 0; i TotNum; i+) /给矩阵赋初值。 for (j = 0; j TotNum; j+) Aij = i; Bij = j; Cij = 0; consoleOutput.append(n Sending information to servers.); try for (i = 0; i NumServers; i+) dataouti.write(TotNum); dataouti.write(NumRows); dataouti.flush(); /给每个服务器依次传送方阵的维数和矩阵A行数。 /下面两个循环分别传送每个服务器所需计算的矩阵。 /对矩阵A按行划分为若干部分,每部分为NumRows行,最后一部分可能不足 /NumRows行,则单独传送。 for (j = NumRows * i; j NumRows * (i + 1); j+) for (k = 0; k TotNum; k+) dataouti.writeInt(Ajk); dataouti.flush(); /对矩阵B没有划分,对每个服务器传送整个矩阵B。 for (j = 0; j TotNum; j+) for (k = 0; k TotNum; k+) dataouti.writeInt(Bjk); dataouti.flush(); catch (IOException ioe) consoleOutput.append(n I/O error reading matrix to server); System.exit(1); try /从每个服务器读取计算结果。 for (i = 0; i NumServers; i+) for (j = NumRows * i; j NumRows * (i + 1); j+) for (k = 0; k TotNum; k+) Cjk = dataini.readInt(); catch (IOException ioe) consoleOutput.append(n I/O error receiving result from server); System.exit(1); consoleOutput.append(n Resultant Matrix); consoleOutput.append(n); for (i = 0; i TotNum; i+) /输出计算结果。 for (j = 0; j TotNum; j+) consoleOutput.append(Cij + ); consoleOutput.append(n); public Netc(JTextArea console) consoleOutput = console; start(); 服务端的实现代码FrmS类:import java.awt.*;import java.awt.event.*;import javax.swing.*;public class FrmS extends JFrame implements ActionListener public JTextArea console = new JTextArea(服务端运行状态信息.n); JPanel jPanel1 = new JPanel(); BorderLayout borderLayout1 = new BorderLayout(); JPanel jPanel2 = new JPanel(); JButton listenPort = new JButton(); JScrollPane jScrollPane = new JScrollPane(); public FrmS() setSize(300, 400); setLocation(300, 200); jPanel1.setLayout(borderLayout1); this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setTitle(服务器端); listenPort.setText(开始监听端口1237); listenPort.addActionListener(this); jPanel2.add(listenPort, new FlowLayout(); jPanel1.add(jPanel2, BorderLayout.NORTH); jScrollPane.getViewport().add(console); jPanel1.add(jScrollPane, BorderLayout.CENTER); this.getContentPane().add(jPanel1, BorderLayout.CENTER); public void actionPerformed(ActionEvent e) new Nets(console); listenPort.setText(正在监听1237端口(再单击退出); public static v

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论