首页 第二章SOCKET编程

第二章SOCKET编程

举报
开通vip

第二章SOCKET编程基于URL的高层次Java网络编程 URL(UniformResourceLocator)是一致资源定位器的简称,它表示Internet上某一资源的地址。通过URL我们可以访问Internet上的各种网络资源,比如最常见的WWW,FTP站点。浏览器通过解析给定的URL可以在网络上查找相应的文件或其他资源。  URL是最为直观的一种网络定位方法。使用URL符合人们的语言习惯,容易记忆,所以应用十分广泛。而且在目前使用最为广泛的TCP/IP中对于URL中主机名的解析也是协议的一个标准,即所谓的域名解析服务。使用URL进...

第二章SOCKET编程
基于URL的高层次Java网络编程 URL(UniformResourceLocator)是一致资源定位器的简称,它 关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf 示Internet上某一资源的地址。通过URL我们可以访问Internet上的各种网络资源,比如最常见的WWW,FTP站点。浏览器通过解析给定的URL可以在网络上查找相应的文件或其他资源。  URL是最为直观的一种网络定位 方法 快递客服问题件处理详细方法山木方法pdf计算方法pdf华与华方法下载八字理论方法下载 。使用URL符合人们的语言习惯,容易记忆,所以应用十分广泛。而且在目前使用最为广泛的TCP/IP中对于URL中主机名的解析也是 协议 离婚协议模板下载合伙人协议 下载渠道分销协议免费下载敬业协议下载授课协议下载 的一个 标准 excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载 ,即所谓的域名解析服务。使用URL进行网络编程,不需要对协议本身有太多的了解,功能也比较弱,相对而言是比较简单的,所以在这里我们先介绍在Java中如何使用URL进行网络编程来引导读者入门。URL的组成protocol://resourceName  协议名(protocol)指明获取资源所使用的传输协议,如http、ftp、gopher、file等,资源名(resourceName)则应该是资源的完整地址,包括主机名、端口号、文件名或文件内部的一个引用。例如:  http://www.sun.com/协议名://主机名  http://home.netscape.com/home/welcome.html协议名://机器名+文件名http://www.gamelan.com:80/Gamelan/network.html#BOTTOM协议名://机器名+端口号+文件名+内部引用 端口号是和Socket编程相关的一个概念,初学者不必在此深究,在后面会有详细讲解。内部引用是HTML中的标记,有兴趣的读者可以参考有关HTML的书籍。创建一个URL为了表示URL,java.net中实现了类URL。我们可以通过下面的构造方法来初始化一个URL对象:(1)publicURL(Stringspec);     通过一个表示URL地址的字符串可以构造一个URL对象。     URLurlBase=newURL(“http://www.263.net/”)(2)publicURL(URLcontext,Stringspec);     通过基URL和相对URL构造一个URL对象。     URLnet263=newURL(“http://www.263.net/”);     URLindex263=newURL(net263,“index.html”)(3)publicURL(Stringprotocol,Stringhost,Stringfile); newURL(“http”,“www.gamelan.com”,“/pages/Gamelan.net.html”);(4)publicURL(Stringprotocol,Stringhost,intport,Stringfile);URLgamelan=newURL("http","www.gamelan.com",80,"Pages/Gamelan.network.html");注意:类URL的构造方法都声明抛弃非运行时例外(MalformedURLException),因此生成URL对象时,我们必须要对这一例外进行处理,通常是用try-catch语句进行捕获。格式如下:  try{     URLmyURL=newURL(…)  }catch(MalformedURLExceptione){  …  //exceptionhandlercodehere  …  }一个URL对象生成后,其属性是不能被改变的,但是我们可以通过类URL所提供的方法来获取这些属性:   publicStringgetProtocol()获取该URL的协议名。   publicStringgetHost()获取该URL的主机名。   publicintgetPort()获取该URL的端口号,如果没有设置端口,返回-1。   publicStringgetFile()获取该URL的文件名。   publicStringgetRef()获取该URL在文件中的相对位置。   publicStringgetQuery()获取该URL的查询信息。   publicStringgetPath()获取该URL的路径   publicStringgetAuthority()获取该URL的权限信息   publicStringgetUserInfo()获得使用者的信息   publicStringgetRef()获得该URL的锚下面的例子中,我们生成一个URL对象,并获取它的各个属性。  importjava.net.*;  importjava.io.*;  publicclassParseURL{  publicstaticvoidmain(String[]args)throwsException{  URLAurl=newURL("http://java.sun.com:80/docs/books/");  URLtuto=newURL(Aurl,"tutorial.intro.html#DOWNLOADING");  System.out.println("protocol="+tuto.getProtocol());  System.out.println("host="+tuto.getHost());  System.out.println("filename="+tuto.getFile());  System.out.println("port="+tuto.getPort());  System.out.println("ref="+tuto.getRef());  System.out.println("query="+tuto.getQuery());  System.out.println("path="+tuto.getPath());  System.out.println("UserInfo="+tuto.getUserInfo());  System.out.println("Authority="+tuto.getAuthority());  }  } 当我们得到一个URL对象后,就可以通过它读取指定的WWW资源。这时我们将使用URL的方法openStream(),其定义为:         InputStreamopenStream();    方法openSteam()与指定的URL建立连接并返回InputStream类的对象以从这一连接中读取数据。  publicclassURLReader{  publicstaticvoidmain(String[]args)throwsException{          //声明抛出所有例外    URLtirc=newURL(“http://www.tirc1.cs.tsinghua.edu.cn/”);        //构建一URL对象    BufferedReaderin=newBufferedReader(newInputStreamReader(tirc.openStream()));//使用openStream得到一输入流并由此构造一个BufferedReader对象    StringinputLine;    while((inputLine=in.readLine())!=null)    //从输入流不断的读数据,直到读完为止    System.out.println(inputLine);//把读入的数据打印到屏幕上    in.close();//关闭输入流  }  }通过URL的方法openStream(),我们只能从网络上读取数据,如果我们同时还想输出数据,例如向服务器端的CGI程序发送一些数据,我们必须先与URL建立连接,然后才能对其进行读写,这时就要用到类URLConnection了。CGI是公共网关接口(CommonGatewayInterface)的简称,它是用户浏览器和服务器端的应用程序进行连接的接口,有关CGI程序设计,请读者参考有关书籍。类URLConnection也在包java.net中定义,它表示Java程序和URL在网络上的通信连接。当与一个URL建立连接时,首先要在一个URL对象上通过方法openConnection()生成对应的URLConnection对象。例如下面的程序段首先生成一个指向地址http://edu.chinaren.com/index.shtml的对象,然后用openConnection()打开该URL对象上的一个连接,返回一个URLConnection对象。如果连接过程失败,将产生IOException.Try{    URLnetchinaren=newURL("http://edu.chinaren.com/index.shtml");    URLConnectonntc=netchinaren.openConnection();  }catch(MalformedURLExceptione){//创建URL()对象失败  …  }catch(IOExceptione){//openConnection()失败  …  }类URLConnection提供了很多方法来设置或获取连接参数,程序设计时最常使用的是getInputStream()和getOutputStream(),其定义为:    InputSteramgetInputSteram();    OutputSteramgetOutputStream();通过返回的输入/输出流我们可以与远程对象进行通信。看下面的例子: URLurl=newURL("http://www.javasoft.com/cgi-bin/backwards");  //创建一URL对象  URLConnectincon=url.openConnection(); //由URL对象获取URLConnection对象DataInputStreamdis=newDataInputStream(con.getInputSteam());  //由URLConnection获取输入流,并构造DataInputStream对象PrintStreamps=newPrintSteam(con.getOutupSteam());  //由URLConnection获取输出流,并构造PrintStream对象 Stringline=dis.readLine();//从服务器读入一行  ps.println("client…");//向服务器写出字符串"client…"    其中backwards为服务器端的CGI程序。实际上,类URL的方法openSteam()是通过URLConnection来实现的。它等价于    openConnection().getInputStream();基于URL的网络编程在底层其实还是基于下面要讲的Socket接口的。WWW,FTP等标准化的网络服务都是基于TCP协议的,所以本质上讲URL编程也是基于TCP的一种应用。选择1、URLurl=newURL(http://freemail.263.net);那么url.getFile()得到的结果是:A263BnetCnullD""二、多项选择1、关于TCP/IP协议下面哪几点是错误的?ATCP/IP协议由TCP协议和IP协议组成BTCP和UDP都是TCP/IP协议传输层的子协议CSocket是TCP/IP协议的一部分D主机名的解析是TCP/IP的一部分2、下面哪些URL是合法的Ahttp://166.111.136.3/index.htmlBftp://166.111.136.3/incomingCftp://166.111.136.3:-1/Dhttp://166.111.136.3.33、下面哪几种方法是表示本机的AlocalhostB255.255.255.255C127.0.0.1D123.456.0.0基于Socket(套接字)的低层次Java网络编程网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定。  在传统的UNIX环境下可以操作TCP/IP协议的接口不止Socket一个,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。  说Socket编程是低层次网络编程并不等于它功能不强大,恰恰相反,正因为层次低,Socket编程比基于URL的网络编程提供了更强大的功能和更灵活的控制,但是却要更复杂一些。由于Java本身的特殊性,Socket编程在Java中可能已经是层次最低的网络编程接口,在Java中要直接操作协议中更低的层次,需要使用Java的本地方法调用(JNI),在这里就不予讨论了。使用Socket进行Client/Server程序设计的一般连接过程是这样的:Server端Listen(监听)某个端口是否有连接请求,Client端向Server端发出Connect(连接)请求,Server端向Client端发回Accept(接受)消息。一个连接就建立起来了。Server端和Client端都可以通过Send,Write等方法与对方通信。对于一个功能齐全的Socket,都要包含以下基本结构,其工作过程包含以下四个基本的 步骤 新产品开发流程的步骤课题研究的五个步骤成本核算步骤微型课题研究步骤数控铣床操作步骤 :(1)创建Socket;(2)打开连接到Socket的输入/出流(3)按照一定的协议对Socket进行读/写操作;(4)关闭Socket.  第三步是程序员用来调用Socket和实现程序功能的关键步骤,其他三步在各种程序中基本相同。  以上4个步骤是针对TCP传输而言的,使用UDP进行传输时略有不同,在后面会有具体讲解。创建Socketjava在包java.net中提供了两个类Socket和ServerSocket,分别用来表示双向连接的客户端和服务端。这是两个封装得非常好的类,使用很方便。其构造方法如下:  Socket(InetAddressaddress,intport);  Socket(InetAddressaddress,intport,booleanstream);  Socket(Stringhost,intprot);  Socket(Stringhost,intprot,booleanstream);  Socket(SocketImplimpl)Socket(Stringhost,intport,InetAddresslocalAddr,intlocalPort)Socket(InetAddressaddress,intport,InetAddresslocalAddr,intlocalPort)  ServerSocket(intport);  ServerSocket(intport,intbacklog);  ServerSocket(intport,intbacklog,InetAddressbindAddr);其中address、host和port分别是双向连接中另一方的IP地址、主机名和端口号,stream指明socket是流socket还是数据报socket,localPort表示本地主机的端口号,localAddr和bindAddr是本地机器的地址(ServerSocket的主机地址),impl是socket的父类,既可以用来创建serverSocket又可以用来创建Socket。count则表示服务端所能支持的最大连接数。例如:  Socketclient=newSocket("127.0.01.",80);  ServerSocketserver=newServerSocket(80);注意,在选择端口时,必须小心。每一个端口提供一种特定的服务,只有给出正确的端口,才能获得相应的服务。0~1023的端口号为系统所保留,例如http服务的端口号为80,telnet服务的端口号为21,ftp服务的端口号为23,所以我们在选择端口号时,最好选择一个大于1023的数以防止发生冲突。在创建socket时如果发生错误,将产生IOException,在程序中必须对之作出处理。所以在创建Socket或ServerSocket是必须捕获或抛出例外。下面是一个典型的创建客户端Socket的过程。   try{     Socketsocket=newSocket("127.0.0.1",4700);     //127.0.0.1是TCP/IP协议中默认的本机地址   }catch(IOExceptione){     System.out.println("Error:"+e);   }这是最简单的在客户端创建一个Socket的一个小程序段,也是使用Socket进行网络通讯的第一步,程序相当简单,在这里不作过多解释了。在后面的程序中会用到该小程序段。下面是一个典型的创建Server端ServerSocket的过程。  ServerSocketserver=null;  try{     server=newServerSocket(4700); //创建一个ServerSocket在端口4700监听客户请求  }catch(IOExceptione){     System.out.println(“cannotlistento:”+e);  }  Socketsocket=null;  try{    socket=server.accept();//accept()是一个阻塞的方法,一旦有客户请求,它就会返回一个Socket对象用于同客户进行交互  }catch(IOExceptione){    System.out.println("Error:"+e);  } 以上的程序是Server的典型工作模式,只不过在这里Server只能接收一个请求,接受完后Server就退出了。实际的应用中总是让它不停的循环接收,一旦有客户请求,Server总是会创建一个服务线程来服务新来的客户,而自己继续监听。程序中accept()是一个阻塞函数,所谓阻塞性方法就是说该方法被调用后,将等待客户的请求,直到有一个客户启动并请求连接到相同的端口,然后accept()返回一个对应于客户的socket。这时,客户方和服务方都建立了用于通信的socket,接下来就是由各个socket分别打开各自的输入/输出流。打开输入/出流类Socket提供了方法getInputStream()和getOutStream()来得到对应的输入/输出流以进行读/写操作,这两个方法分别返回InputStream和OutputSteam类对象。为了便于读/写数据,我们可以在返回的输入/输出流对象上建立过滤流,如DataInputStream、DataOutputStream或PrintStream类对象,对于文本方式流对象,可以采用InputStreamReader和OutputStreamWriter、PrintWirter等处理。例如:  PrintStreamos=newPrintStream(newBufferedOutputStreem(socket.getOutputStream()));  DataInputStreamis=newDataInputStream(socket.getInputStream());  PrintWriterout=newPrintWriter(socket.getOutStream(),true);  BufferedReaderin=newButfferedReader(newInputSteramReader(Socket.getInputStream()));输入输出流是网络编程的实质性部分,具体如何构造所需要的过滤流,要根据需要而定,能否运用自如主要看读者对Java中输入输出部分掌握如何。 每一个Socket存在时,都将占用一定的资源,在Socket对象使用完毕时,要其关闭。关闭Socket可以调用Socket的Close()方法。在关闭Socket之前,应将与Socket相关的所有的输入/输出流全部关闭,以释放所有的资源。而且要注意关闭的顺序,与Socket相关的所有的输入/输出该首先关闭,然后再关闭Socket。  os.close();  is.close();  socket.close();  尽管Java有自动回收机制,网络资源最终是会被释放的。但是为了有效的利用资源,建议读者按照合理的顺序主动释放资源。简单的Client/Server程序设计 下面我们给出一个用Socket实现的客户和服务器交互的典型的C/S结构的演示程序,读者通过仔细阅读该程序,会对前面所讨论的各个概念有更深刻的认识。程序的意义请参考注释。1.客户端程序importjava.io.*;  importjava.net.*;  publicclassTalkClient{    publicstaticvoidmain(Stringargs[]){      try{        Socketsocket=newSocket(“127.0.0.1”,4700);        //向本机的4700端口发出客户请求BufferedReadersin=newBufferedReader(newInputStreamReader(System.in));        //由系统标准输入设备构造BufferedReader对象PrintWriteros=newPrintWriter(socket.getOutputStream());     //由Socket对象得到输出流,并构造PrintWriter对象BufferedReaderis=newBufferedReader(newInputStreamReader(socket.getInputStream()));  //由Socket对象得到输入流,并构造相应的BufferedReader对象       Stringreadline;readline=sin.readLine();//从系统标准输入读入一字符串while(!readline.equals(“bye”)){        //若从标准输入读入的字符串为“bye”则停止循环          os.println(readline);//将从系统标准输入读入的字符串输出到Server          os.flush();//刷新输出流,使Server马上收到该字符串          System.out.println(“Client:”+readline);          //在系统标准输出上打印读入的字符串          System.out.println(“Server:”+is.readLine());          //从Server读入一字符串,并打印到标准输出上         readline=sin.readLine();//从系统标准输入读入一字符串        }//继续循环        os.close();//关闭Socket输出流        is.close();//关闭Socket输入流        socket.close();//关闭Socket      }catch(Exceptione){        System.out.println("Error"+e);//出错,则打印出错信息      }  }}2.服务器端程序importjava.io.*;  importjava.net.*;  importjava.applet.Applet;  publicclassTalkServer{    publicstaticvoidmain(Stringargs[]){      try{        ServerSocketserver=null;        try{          server=newServerSocket(4700);        //创建一个ServerSocket在端口4700监听客户请求        }catch(Exceptione){          System.out.println("cannotlistento:"+e);        //出错,打印出错信息        }Socketsocket=null;        try{          socket=server.accept();        //使用accept()阻塞等待客户请求,有客户        //请求到来则产生一个Socket对象,并继续执行        }catch(Exceptione){          System.out.println(“Error.”+e);          //出错,打印出错信息        }        Stringline;BufferedReaderis=newBufferedReader(newInputStreamReader(socket.getInputStream())); //由Socket对象得到输入流,并构造相应的BufferedReader对象        PrintWriteros=newPrintWriter(socket.getOutputStream());      //由Socket对象得到输出流,并构造PrintWriter对象BufferedReadersin=newBufferedReader(newInputStreamReader(System.in));         //由系统标准输入设备构造BufferedReader对象System.out.println("Client:"+is.readLine());        //在标准输出上打印从客户端读入的字符串        line=sin.readLine();        //从标准输入读入一字符串        while(!line.equals("bye")){        //如果该字符串为"bye",则停止循环          os.println(line);        //向客户端输出该字符串          os.flush();        //刷新输出流,使Client马上收到该字符串          System.out.println("Server:"+line);        //在系统标准输出上打印读入的字符串          System.out.println("Client:"+is.readLine());//从Client读入一字符串,并打印到标准输出上          line=sin.readLine();          //从系统标准输入读入一字符串        } //继续循环os.close();//关闭Socket输出流      is.close();//关闭Socket输入流      socket.close();//关闭Socket      server.close();//关闭ServerSocket      }catch(Exceptione){        System.out.println("Error:"+e);        //出错,打印出错信息      }    }  }从上面的两个程序中我们可以看到,socket四个步骤的使用过程。读者可以分别将Socket使用的四个步骤的对应程序段选择出来,这样便于读者对socket的使用有进一步的了解。  读者可以在单机上试验该程序,最好是能在真正的网络环境下试验该程序,这样更容易分辨输出的内容和客户机,服务器的对应关系。同时也可以修改该程序,提供更为强大的功能,或更加满足读者的意图。多选题1。下面正确的创建Socket的语句有?ASocketa=newSocket(80);BSocketb=newSocket("130.3.4.5",80);CServerSocketc=newSocket(80)DServerSocketd=newSocket("130.3.4.5",80)下面关于阻塞函数的论述,正确的有?A阻塞函数是指无法返回的函数B阻塞函数是指网络过于繁忙,函数必须等待C阻塞函数是指有外部事件发生才会返回的函数。D阻塞函数如果不能马上返回,就会进入等待状态,把系统资源让给其他线程单选欲构造ArrayList类的一个实例,此类继承了List接口,下列哪个方法是正确的?AArrayListmyList=newObject();BListmyList=newArrayList();CArrayListmyList=newList();DListmyList=newList();支持多客户的client/server程序设计前面提供的Client/Server程序只能实现Server和一个客户的对话。在实际应用中,往往是在服务器上运行一个永久的程序,它可以接收来自其他多个客户端的请求,提供相应的服务。为了实现在服务器方给多个客户提供服务的功能,需要对上面的程序进行改造,利用多线程实现多客户机制。服务器总是在指定的端口上监听是否有客户请求,一旦监听到客户请求,服务器就会启动一个专门的服务线程来响应该客户的请求,而服务器本身在启动完线程之后马上又进入监听状态,等待下一个客户的到来。线程简介随着计算机的飞速发展,个人计算机上的操作系统也纷纷采用多任务和分时设计,将早期只有大型计算机才具有的系统特性带到了个人计算机系统中。一般可以在同一时间内执行多个程序的操作系统都有进程的概念。一个进程就是一个执行中的程序,而每一个进程都有自己独立的一块内存空间、一组系统资源。在进程概念中,每一个进程的内部数据和状态都是完全独立的。Java程序通过流控制来执行程序流,程序中单个顺序的流控制称为线程,多线程则指的是在单个程序中可以同时运行多个不同的线程,执行不同的任务。多线程意味着一个程序的多行语句可以看上去几乎在同一时间内同时运行。线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制;但与进程不同的是,同类的多个线程是共享一块内存空间和一组系统资源,而线程本身的数据通常只有微处理器的寄存器数据,以及一个供程序执行时使用的堆栈。所以系统在产生一个线程,或者在各个线程之间切换时,负担要比进程小的多,正因如此,线程被称为轻负荷进程(light-weightprocess)。一个进程中可以包含多个线程。一个线程是一个程序内部的顺序控制流。  1.进程:每个进程都有独立的代码和数据空间(进程上下文),进程切换的开销大。  2.线程:轻量的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小。  3.多进程:在操作系统中,能同时运行多个任务程序。  4.多线程:在同一应用程序中,有多个顺序流同时执行。Java内在支持多线程,它的所有类都是在多线程下定义的,Java利用多线程使整个系统成为异步系统。Java中的线程由三部分组成。1.虚拟的CPU,封装在java.lang.Thread类中。2.CPU所执行的代码,传递给Thread类。3.CPU所处理的数据,传递给Thread类。线程体(1)Java的线程是通过java.lang.Thread类来实现的。当我们生成一个Thread类的对象之后,一个新的线程就产生了。此线程实例表示Java解释器中的真正的线程,通过它可以启动线程、终止线程、线程挂起等,每个线程都是通过类Thread在Java的软件包Java.lang中定义,它的构造方法为:publicThread(ThreadGroupgroup,Runnabletarget,Stringname);  其中,group指明该线程所属的线程组;target实际执行线程体的目标对象,它必须实现接口Runnable;name为线程名。Java中的每个线程都有自己的名称,Java提供了不同Thread类构造器,允许给线程指定名称。如果name为null时,则Java自动提供唯一的名称。当上述构造方法的某个参数为null时,我们可得到下面的几个构造方法:  publicThread();  publicThread(Runnabletarget);  publicThread(Runnabletarget,Stringname);  publicThread(Stringname);  publicThread(ThreadGroupgroup,Runnabletarget);  publicThread(ThreadGroupgroup,Stringname);  一个类声明实现Runnable接口就可以充当线程体,在接口Runnable中只定义了一个方法run(): publicvoidrun();任何实现接口Runnable的对象都可以作为一个线程的目标对象,类Thread本身也实现了接口Runnable,因此我们可以通过两种方法实现线程体。(一)定义一个线程类,它继承线程类Thread并重写其中的方法run(),这时在初始化这个类的实例时,目标target可为null,表示由这个实例对来执行线程体。由于Java只支持单重继承,用这种方法定义的类不能再继承其它父类。  (二)提供一个实现接口Runnable的类作为一个线程的目标对象,在初始化一个Thread类或者Thread子类的线程对象时,把目标对象传递给这个线程实例,由该目标对象提供线程体run()。这时,实现接口Runnable的类仍然可以继承其它父类。每个线程都是通过某个特定Thread对象的方法run()来完成其操作的,方法run()称为线程体。下图表示了java线程的不同状态以及状态之间转换所调用的方法。newThread()NewThreadRunnableNotRunnableStart()Yield()DeadStop()Stop()orRun()Stop()1.创建状态(newThread)  执行下列语句时,线程就处于创建状态:  ThreadmyThread=newMyThreadClass();  当一个线程处于创建状态时,它仅仅是一个空的线程对象,系统不为它分配资源。  2.可运行状态(Runnable)  ThreadmyThread=newMyThreadClass();  myThread.start(); 当一个线程处于可运行状态时,系统为这个线程分配了它需的系统资源,安排其运行并调用线程运行方法,这样就使得该线程处于可运行(Runnable)状态。需要注意的是这一状态并不是运行中状态(Running),因为线程也许实际上并未真正运行。由于很多计算机都是单处理器的,所以要在同一时刻运行所有的处于可运行状态的线程是不可能的,Java的运行系统必须实现调度来保证这些线程共享处理器。 3.不可运行状态(NotRunnable)  进入不可运行状态的原因有如下几条:  1)调用了sleep()方法;  2)调用了suspend()方法;  3)为等候一个条件变量,线程调用wait()方法;  4)输入输出流中发生线程阻塞;  不可运行状态也称为阻塞状态(Blocked)。因为某种原因(输入/输出、等待消息或其它阻塞情况),系统不能执行线程的状态。这时即使处理器空闲,也不能执行该线程。  4.死亡状态(Dead)  线程的终止一般可通过两种方法实现:自然撤消(线程执行完)或是被停止(调用stop()方法)。目前不推荐通过调用stop()来终止线程的执行,而是让线程执行完。◇线程体的构造任何实现接口Runnable的对象都可以作为一个线程的目标对象,上面已讲过构造线程体有两种方法,下面通过实例来说明如何构造线程体的。(1)通过继承类Thread构造线程体(2)通过接口构造线程体通过继承类Thread构造线程体classSimpleThreadextendsThread{  publicSimpleThread(Stringstr){   super(str);//调用其父类的构造方法  }  publicvoidrun(){//重写run方法   for(inti=0;i<10;i++){    System.out.println(i+""+getName());             //打印次数和线程的名字    try{      sleep((int)(Math.random()*1000));             //线程睡眠,把控制权交出去    }catch(InterruptedExceptione){}  }     System.out.println("DONE!"+getName());             //线程执行结束    }  }publicclassTwoThreadsTest{   publicstaticvoidmain(Stringargs[]){    newSimpleThread("First").start();          //第一个线程的名字为First    newSimpleThread("Second").start();        //第二个线程的名字为Second}}通过接口构造线程体 publicclassClockextendsjava.applet.AppletimplementsRunnable{//实现接口      ThreadclockThread;      publicvoidstart(){         //该方法是Applet的方法,不是线程的方法      if(clockThread==null){         clockThread=newThread(this,"Clock");         /*线程体是Clock对象本身,线程名字为"Clock"*/         clockThread.start();//启动线程         }      }  publicvoidrun(){//run()方法中是线程执行的内容         while(clockThread!=null){         repaint();//刷新显示画面         try{           clockThread.sleep(1000);           //睡眠1秒,即每隔1秒执行一次          }catch(InterruptedExceptione){}         }      }      publicvoidpaint(Graphicsg){    Datenow=newDate();//获得当前的时间对象  g.drawString(now.getHours()+":"+now.getMinutes()+":"+now.getSeconds(),5,10);//显示当前时间      }      publicvoidstop(){    //该方法是Applet的方法,不是线程的方法          clockThread.stop();          clockThread=null;      }   } 构造线程体的两种方法的比较:  1.使用Runnable接口   1)可以将CPU,代码和数据分开,形成清晰的模型;   2)还可以从其他类继承;   3)保持程序风格的一致性。  2.直接继承Thread类   1)不能再从其他类继承;   2)编写简单,可以直接操纵线程,无需使用Thread.currentThread()。1.客户端程序:MultiTalkClient.javaimportjava.io.*;  importjava.net.*;  publicclassMultiTalkClient{   publicstaticvoidmain(Stringargs[]){    try{      Socketsocket=newSocket("127.0.0.1",4700);      //向本机的4700端口发出客户请求  BufferedReadersin=newBufferedReader(newInputStreamReader(System.in));      //由系统标准输入设备构造BufferedReader对象  PrintWriteros=newPrintWriter(socket.getOutputStream());      //由Socket对象得到输出流,并构造PrintWriter对象  BufferedReaderis=newBufferedReader(newInputStreamReader(socket.getInputStream()));  //由Socket对象得到输入流,并构造相应的BufferedReader对象      Stringreadline;     readline=sin.readLine();//从系统标准输入读入一字符串while(!readline.equals(“bye”)){      //若从标准输入读入的字符串为“bye”则停止循环        os.println(readline);        //将从系统标准输入读入的字符串输出到Server        os.flush();        //刷新输出流,使Server马上收到该字符串        System.out.println(“Client:”+readline);        //在系统标准输出上打印读入的字符串        System.out.println(“Server:”+is.readLine());        //从Server读入一字符串,并打印到标准输出上        readline=sin.readLine();        //从系统标准输入读入一字符串      }//继续循环 os.close();//关闭Socket输出流      is.close();//关闭Socket输入流      socket.close();//关闭Socket}catch(Exceptione){      System.out.println("Error"+e);//出错,则打印出错信息    }  }}2.服务器端程序:MultiTalkServer.javaimportjava.io.*;  importjava.net.*;  importServerThread;  publicclassMultiTalkServer{   staticintclientnum=0;//静态成员变量,记录当前客户的个数   publicstaticvoidmain(Stringargs[])throwsIOException{    ServerSocketserverSocket=null;    booleanlistening=true;    try{      serverSocket=newServerSocket(4700);      //创建一个ServerSocket在端口4700监听客户请求    }catch(IOExceptione){      System.out.println("Couldnotlistenonport:4700.");      //出错,打印出错信息      System.exit(-1);//退出    }    while(listening){//永远循环监听      newServerThread(serverSocket.accept(),clientnum).start();//监听到客户请求,根据得到的Socket对象和客户计数创建服务线程,并启动之      clientnum++;//增加客户计数    }    serverSocket.close();//关闭ServerSocket}}3.程序ServerThread.javaimportjava.io.*;  importjava.net.*;  publicclassServerThreadextendsThread{   Socketsocket=null;//保存与本线程相关的Socket对象   intclientnum;//保存本进程的客户计数   publicServerThread(Socketsocket,intnum){//构造函数    this.socket=socket;//初始化socket变量    clientnum=num+1;//初始化clientnum变量   }   publicvoidrun(){//线程主体    try{      Stringline;      BufferedReaderis=newBufferedReader(newInputStreamReader(socket.getInputStream()));  //由Socket对象得到输入流,并构造相应的BufferedReader对象PrintWriteros=newPrintWriter(socket.getOutputStream());      //由Socket对象得到输出流,并构造PrintWriter对象      BufferedReadersin=newBufferedReader(newInputStreamReader(System.in));      //由系统标准输入设备构造BufferedReader对象      System.out.println("Client:"+clientnum+is.readLine());      //在标准输出上打印从客户端读入的字符串      line=sin.readLine();      //从标准输入读入一字符串      while(!line.equals("bye")){      //如果该字符串为"bye",则停止循环      os.println(line);        //向客户端输出该字符串      os.flush();        //刷新输出流,使Client马上收到该字符串System.out.println("Server:"+line);        //在系统标准输出上打印该字符串        System.out.println("Client:"+clientnum+is.readLine());        //从Client读入一字符串,并打印到标准输出上        line=sin.readLine();        //从系统标准输入读入一字符串      }//继续循环      os.close();//关闭Socket输出流      is.close();//关闭Socket输入流      socket.close();//关闭Socket      server.close();//关闭ServerSocket     }catch(Exceptione){      System.out.println("Error:"+e);      //出错,打印出错信息     }   } } 这个程序向读者展示了网络应用中最为典型的C/S结构, 通过以上的
本文档为【第二章SOCKET编程】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
个人认证用户
中小学教育资料大全
暂无简介~
格式:ppt
大小:336KB
软件:PowerPoint
页数:67
分类:金融/投资/证券
上传时间:2023-02-20
浏览量:0