1、1,Chapter 11:Java网络编程,授课教师:赵小敏 浙江工业大学 软件学院 Email:,2,主要内容,1、 网络基础知识 2 、基于URL类的Java网络编程 3、Socket和ServerSocket类 4、基于TCP的Java编程 5、基于UDP的Java编程,3,1、 网络基础知识,计算机网络形式多样,内容繁杂。网络上的计算机要互相通信,必须遵循一定的协议。目前使用最广泛的网络协议是Internet上所使用的TCP/IP协议 网络编程是指利用不同层次的通信协议提供的接口实现网络进程通信的编程。 网络编程中有两个主要的问题,一个是如何准确的定位网络上一台或多台主机,另一个就是找
2、到主机后如何可靠高效的进行数据传输。在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一地确定Internet上的一台主机。而TCP层则提供面向应用的可靠的或非可靠的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据的。,4,1、网络基础知识(续2),目前较为流行的网络编程模型是客户机/服务器(C/S)结构。即通信双方一方作为服务器等待客户提出请求并予以响应。客户则在需要服务时向服务器提出申请。服务器一般作为守护进程始终运行,监听网络端口,一旦有客户请求,就会启动一个服务进程来响应该客户,同时自己继续监听服务端口,使后来的客户也能及时得到服
3、务。,5,1、网络基础知识(续3),网络进程是指在网络结点计算机上运行的程序 通信协议指网络进程之间的通信必须遵循预定的规则。 TCP/IP是一组在Internet网络上的不同计算机之间进行通信的协议的总称,它由应用层的HTTP、FTP、SMTP和传输层的TCP及网络层的IP等一系列协议组成。,6,TCP/UDP/IP,TCP(传输控制协议)是面向连接的、可靠的点对点的传输协议。 UDP(用户数据报协议)是无连接的不可可靠的传输协议。 IP是网络层协议,实现按IP地址的网络路由的功能。,7,TCP,通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间
4、必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。,8,UDP,UDP是User Datagram Protocol的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。,9,套接字,“套接字”或者“插座”(Socket)也是一种软件形式的抽象,用于表达两台机器间
5、一个连接的“终端”。 针对一个特定的连接,每台机器上都有一个“套接字”,可以想象它们之间有一条虚拟的“线缆”。线缆的每一端都插入一个“套接字”或者“插座”里。 进程之间要实现通信首先要建立各自的套接字。 在Java中,我们创建一个套接字,用它建立与其他机器的连接。,10,TCP/IP中的端口号,机器内独一无二的场所 有些时候,一个IP地址并不足以完整标识一个服务器。这是由于在一台物理性的机器中,往往运行着多个服务器(程序)。由IP表达的每台机器也包含了“端口”(Port)。 TCP/IP系统中的端口号是16位的数字,从0 65535。一般=1023由预先定义的服务占用,如telnet,SMTP
6、 mail、ftp等。Client 与Server在建立连接前,必须事先约定好端口号。,11,Java网络程序设计支持机制,利用URL访问网络资源 利用Socket通信,支持Socket通信的类,网 络,Java网络应用系统,支持URL的类,12,Java网络程序设计支持机制,支持网络通信的类在包中。 URL, URLConnection, Socket, ServerSocket ,使用TCP实现网络通信。 DatagramPacket, DatagramSocket, MulticastSocket 支持 UDP 通信方式。,13,2、基于URL类的Java网络编程,统一资源定位器URL
7、URL(Uniform Resource Locator)是一致资源定位器的简称,它表示Internet上某一资源的地址。通过URL我们可以访问Internet上的各种网络资源,比如最常见的WWW,FTP站点。浏览器通过解析给定的URL可以在网络上查找相应的文件或其他资源。,14,URL的组成,protocol:/resourceName 协议名(protocol)指明获取资源所使用的传输协议,如http、ftp、gopher、file等,资源名(resourceName)则应该是资源的完整地址,包括主机名、端口号、文件名或文件内部的一个引用。例如: http:/ 协议名:/主机http:/
8、协议名:/机器名文件名 http:/:80/Gamelan/network.html#BOTTOM 协议名:/机器名端口号文件名内部引用,15,创建一个URL,为了表示URL, 中实现了类URL。可以通过下面的构造方法来初始化一个URL对象: (1) public URL (String spec); 通过一个表示URL地址的字符串可以构造一个URL对象。 URL urlBase=new URL(“http:/www. (2) public URL(URL context, String spec); 通过基URL和相对URL构造一个URL对象。 URL net263=new URL (“h
9、ttp:/ URL index263=new URL(net263, “index.html“),16,创建一个URL (续),(3) public URL(String protocol, String host, String file); new URL(“http“, ““, “/pages/G. html“); (4) public URL(String protocol, String host, int port, String file); URL gamelan=new URL(“http“, ““, 80, “Pages/Gwork.html“);,17,创建一个URL (
10、续),注意:类URL的构造方法都声明抛弃非运行时例外(MalformedURLException),因此生成URL对象时,我们必须要对这一例外进行处理,通常是用try-catch语句进行捕获。格式如下: try URL myURL= new URL() catch (MalformedURLException e) /exception handler code here ,18,解析一个URL,一个URL对象生成后,其属性是不能被改变的,但是我们可以通过类URL所提供的方法来获取这些属性: public String getProtocol() 获取该URL的协议名。 public Stri
11、ng getHost() 获取该URL的主机名。 public int getPort() 获取该URL的端口号,如果没有设置端口,返回-1。 public String getFile() 获取该URL的文件名。 public String getRef() 获取该URL在文件中的相对位置。 public String getQuery() 获取该URL的查询信息。 public String getPath() 获取该URL的路径 public String getAuthority() 获取该URL的权限信息 public String getUserInfo() 获得使用者的信息 pu
12、blic String getRef() 获得该URL的锚,19,import .*; import java.io.*;public class ParseURL public static void main(String args) throws Exception URL aURL = new URL(“http:/:80/docs/books/“+ “tutorial/index.html#DOWNLOADING“);System.out.println(“protocol = “ + aURL.getProtocol();System.out.println(“host = “ +
13、 aURL.getHost();System.out.println(“filename = “ + aURL.getFile();System.out.println(“port = “ + aURL.getPort(); System.out.println(“ref = “ + aURL.getRef(); ,20,从URL读取WWW网络资源,当我们得到一个URL对象后,就可以通过它读取指定的WWW资源。这时我们将使用URL的方法openStream(),其定义为: InputStream openStream(); 方法openSteam()与指定的URL建立连接并返回InputStr
14、eam类的对象以从这一连接中读取数据。,public class URLReader public static void main(String args) throws Exception /声明抛出所有例外URL tirc = new URL(“http:/ /构建一个URL对象BufferedReader in = new BufferedReader(new InputStreamReader(tirc.openStream();/使用openStream得到一个输入流,并由此构建一个BufferedReader对象String inputLine; File outfile = n
15、ew File(“test.html“); PrintWriter out = new PrintWriter(new FileWriter(outfile);while (inputLine = in.readLine() != null) /从输入流中不断读取数据直到读完为止out.println(inputLine); /把读入的数据写入test.htmlin.close(); /关闭输入流out.close();,22,通过URLConnetction连接WWW,通过URL的方法openStream(),我们只能从网络上读取数据,如果我们同时还想输出数据,例如向服务器端的CGI程序发送
16、一些数据,我们必须先与URL建立连接,然后才能对其进行读写,这时就要用到类URLConnection了。 类URLConnection也在包中定义,它表示Java程序和URL在网络上的通信连接。当与一个URL建立连接时,首先要在一个URL对象上通过方法openConnection()生成对应的URLConnection对象。,23,下面的程序段首先生成一个指向地址http:/ URL zjut = new URL (“http:/ URLConnectonn tc = zjut.openConnection(); catch(MalformedURLException e) /创建URL()对
17、象失败 catch (IOException e) /openConnection()失败 ,24,类URLConnection,类URLConnection提供了很多方法来设置或获取连接参数,程序设计时最常使用的是getInputStream()和getOurputStream(),其定义为: InputSteram getInputSteram(); OutputSteram getOutputStream();,25,通过返回的输入/输出流我们可以与远程对象进行通信,URL url =new URL (“http:/ /创建一URL对象 URLConnectin con=url.open
18、Connection(); /由URL对象获取URLConnection对象 DataInputStream dis=new DataInputStream (con.getInputSteam(); /由URLConnection获取输入流,并构造DataInputStream对 PrintStream ps=new PrintSteam(con.getOutupSteam(); /由URLConnection获取输出流,并构造PrintStream对象 String line=dis.readLine(); /从服务器读入一行 ps.println(“client“); /向服务器写出字符
19、串 “client“,26,3、 Socket和ServerSocket类,客户套接字类(Socket) 服务器套接字类(ServerSocket),27,套接字类Socket,1、 Socket的四种构造方法 (1) Socket(String host,int port) thows UnknownHostException,IOException创建一个面向连接的套接字对象,并将其连接至特定的主机(host)的特定端口(port) (2) Socket(String host,int port,boolean stream)创建一个套接字对象,并将其连接至特定的主机的特定端口上,此套接字
20、对象是面向连接的还是数据报的,则由最后的一个参数决定,28,套接字类Socket,1、 Socket的四种构造方法 (3) Socket(InetAddress address,int port)创建一个面向连接的套接字对象,并将其连接至特定IP的主机的特定端口(port) (4) Socket( InetAddress address ,int port,boolean stream)创建一个套接字对象,并将其连接至特定ip主机的特定端口上,此套接字对象是面向连接的还是数据报的,则由最后的一个参数决定,29,套接字类Socket,2、 Socket提供的主要方法 (1) InetAddres
21、s getInetAddress()返回该套接字所连接的IP地址 (2) Int getPort()返回该套接字所连接的远程端口 (3) sychronized void close() throws IOException关闭套接字,30,套接字类Socket,2、 Socket提供的主要方法 (4) InputStream getInputStream () throws IOException获得套接字绑定的数据的输入流 (5) PrintStream getOutputStream() throws IOException获得向套接字绑定的数据输出流,31,服务器套接字(ServerS
22、ocket),1、ServerSocket类的构造方法 (1) ServerSocket(int port) throws IOException构造一个ServerSocket对象,其绑定的端口号为port (2) ServerSocket(int port , int count) 构造一个ServerSocket对象,其绑定的端口号为port,如port为0,则该对象与缺省的端口号绑定。其中count为该对象端口上等待的连接的客户最大数,32,服务器套接字(ServerSocket),2、ServerSocket类的主要方法 (1) Socket accept() throws IOEx
23、ception等待客户连接,该方法将阻塞当前系统服务线程,直到连接成功。该方法返回一个套接字类对象,通过该套接字,新的服务子线程与连接的客户进行通信。 (2) Void close() throws IOException关闭套接字,33,怎样用socket进行客户与服务器通信,Socket是两个实体之间进行通信的有效端点。通过socket可以获得源IP地址和源端口、终点IP地址和终点端口。用户可以将多个socket连入同一个端口,以便对于单个端口可以有多个连接。通过socket客户/服务器编程可以创建一个能被许多人使用的分布式程序,并且所有客户均可以用统一的前端进行工作,并与服务器进行通信。
24、,34,与服务器通信必须具备三个条件,服务器程序 客户程序 连接它们的socket程序,35,ServerSocket类,它的实例使服务器能够检测到指定端口的信息 accept()方法可以使服务器检测到指定端口的活动 服务器还负责检测要求与它连接的客户。,36,Socket类,getInputStream()和getOutStream()方法来发送和捕捉数据。try /传递给它一个整数作为服务器指定可以使用的给定端口 ServerSocket myServerSocket=new ServerSocket(100); Socket my100Socket=myServerSocket.acce
25、pt(); /检测端口的活动 catch(Exception e),37,Accept()方法直到接收到用户的连接请求,才继续执行中断的执行程序。一旦客户的连接成功,my100Socket就代表该连接,并且可以发送和接收数据。 最后,我们看一看客户是怎样请求连接的。其连接方法如下: try Socket mySocket=new Socket(““,100); catch(Exception e ),Socket类,38,4、基于TCP的Java网络编程,一对一的Socket C/S通信TCP是面向连接的、可靠的网络传输协议,当两个网络进程准备进行通信时,都必须首先建立各自的一个套接字,其中服
26、务器建立套接字后,侦听来自网络的客户连接请求,客户通过套接字,指定服务器的IP地址和端口号,便可与服务器进行通信。,39,基于TCP的C/S连接方式,基于连接的服务器、客户程序流程,Socket(),accept(),阻塞、等客户连接请求,read(),处理服务请求,write(),时 间,服务器,Socket(),connet(),write,read,客 户,建立连接,服务请求,服务响应,41,(一)TCP协议通信的服务器方实现,(1) 假设服务器工作在端口8000上, ServerSocket svrsoc ServerSocket(8000) Socket socsvrsoc.acce
27、pt();/监视端口8000的连接请求 (2) 打开与soc绑定的输入/输出流: In=new BufferedReader(new InputStreamRead(soc.getInputStream(); /在套接字soc上绑定的输入流基础上构造BufferedReader对象,42,(一) TCP协议通信的服务器方实现(续),out=new PrintWrite(new bufferedWrite(new OutputStreamWrite(soc.getOutputStream(),true); /在套接字soc上绑定的输出流基础上构造PrintWrite对象 服务器使用in和out两
28、个实例从客户接收输入信息和向客户程序发信息,同样,在客户端也应该建立这两个对象,用来与服务器程序进行双向通信。,43,44,(一) TCP协议通信的服务器方实现(续),(3) 获取客户机的IP地址,并在服务器窗口中显示客户机的地址信息: clientIP=soc.getInetAddress(); System.out.println(“Clients IP address:”+clientIP);,45,(一) TCP协议通信的服务器方实现(续),(4) 读入一行客户的输入,并回显该行String strin.readLine();while(!str.equals(“quit”);Syst
29、em.out.println(“Client said:”+str);str=in.readLine();,46,(一) TCP协议通信的服务器方实现(续),(5) 不断循环以上代码,直到客户输入“quit”为止。 System.out.println(“Client want to leave.”); finallin.close();out.close();soc.close();svrsoc.close(); ,47,(二) TCP协议通信的客户方实现,(1)创建一个指向固定主机的固定端口的Socket:Socket socnew Socket(“localhost”,8000); (2
30、) 从Socket对象中获取与其绑定的输入和输出流 In=new BufferedReader(new InputStreamRead(soc.getInputStream(); out=new PrintWrite(new bufferedWrite(new OutputStreamWrite(soc.getOutputStream(),true);,48,(二) TCP协议通信的客户方实现(续),(3)建立输入/输出流后,从服务器读取发来的”welcome!”信息,显示在窗口: Strin=in.readLine(); System.out.println(“Server said:”+s
31、trin);,49,(二) TCP协议通信的客户方实现(续),(4)客户向服务器发送的数据流从键盘获取 byte bmsg=new byte200; System.in.read(bmsg); /从键盘读入bmsg String msg=new String(bmsg,0); /byte型转String型 Msg=msg.trim(); /删除msg两边的空格,50,(二) TCP协议通信的客户方实现(续),(5)当键盘输入不是“quit”时,将键盘输入的数据写入输出流中,并发送出去,然后继续从键盘获取输入数据,不断循环,直到输入“quit”时,先将其传送给服务器,然后关闭输入/输出流和Soc
32、ket: out.println(strout); In.close(); out.close(); soc.close(); System.exit(0);,一个简单的客户端/服务器程序,import .*; import java.io.*; import java.lang.*; public class myserver public static void main(String args) ServerSocket server; Socket socket; String s; InputStream Is; OutputStream Os; DataInputStream DI
33、S; PrintStream PS; try server=new ServerSocket(4321); socket=server.accept();System.out.println(“server ok“); System.out.println(“*“); System.out.println(“);,Is=socket.getInputStream(); Os=socket.getOutputStream(); DIS=new DataInputStream(Is); PS=new PrintStream(Os); DataInputStream in=new DataInput
34、Stream(System.in); while(true) System.out.println(“); System.out.println(“please wait clients message.“); System.out.println(“); s=DIS.readLine(); System.out.println(“client said:“+s); if(s.trim().equals(“BYE“)break; System.out.print(“you say:“); s=in.readLine(); PS.println(s); if(s.trim().equals(“B
35、YE“)break; DIS.close(); PS.close(); Is.close(); Os.close(); socket.close(); catch(Exception e) System.out.println(“Error:“+e); /catch /main /public class,import .*; import java.io.*; import java.lang.*; public class myclient public static void main(String args) if (args.length1)System.out.println(“P
36、lease input the Server Name or IP!“); System.out.println(“see also: myclient 127.0.0.1“); System.exit(1); /ifSocket socket; String s=““; String len; InputStream Is; OutputStream Os; DataInputStream DIS; PrintStream PS; try socket=new Socket(args0,4321); System.out.println(“client ok“); System.out.pr
37、intln(“*“); System.out.println(“);,Is=socket.getInputStream(); Os=socket.getOutputStream(); DIS=new DataInputStream(Is); PS=new PrintStream(Os); DataInputStream in=new DataInputStream(System.in); while(true) System.out.print(“you say:“); s=in.readLine(); PS.println(s); if(s.trim().equals(“BYE“)break
38、; /else System.out.println(“); System.out.println(“please wait servers message.“); System.out.println(“); s=DIS.readLine(); /System.out.println(“server said:“+s); if(s.trim().equals(“BYE“)break; DIS.close(); /PS.close(); /Is.close(); /Os.close(); / socket.close(); / catch(Exception e) System.out.pri
39、ntln(“Error:“+e); ,55,(三)支持多客户的client/server程序设计,在实际应用中,往往是在服务器上运行一个永久的程序,它可以接收来自其他多个客户端的请求,提供相应的服务。为了实现在服务器方给多个客户提供服务的功能,需要对上面的程序进行改造,利用多线程实现多客户机制。服务器总是在指定的端口上监听是否有客户请求,一旦监听到客户请求,服务器就会启动一个专门的服务线程来响应该客户的请求,而服务器本身在启动完线程之后马上又进入监听状态,等待下一个客户的到来。,import java.io.*; import .*; public class TalkClient publi
40、c static void main(String args) try Socket socket=new Socket(“127.0.0.1”,4700); /向本机的4700端口发出客户请求BufferedReader sin=new BufferedReader(new InputStreamReader(System.in); /由系统标准输入设备构造BufferedReader对象 PrintWriter os=new PrintWriter(socket.getOutputStream(); /由Socket对象得到输出流,并构造PrintWriter对象BufferedReade
41、r is=new BufferedReader(new InputStreamReader(socket.getInputStream(); /由Socket对象得到输入流,并构造相应的BufferedReader对象 String readline; readline=sin.readLine(); /从系统标准输入读入一字符串 while(!readline.equals(“bye”) /若从标准输入读入的字符串为 “bye”则停止循环 os.println(readline); /将从系统标准输入读入的字符串输出到Server os.flush(); /刷新输出流,使Server马上收到
42、该字符串 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(Exception e) System.out.println(“Error”+
43、e); /出错,则打印出错信息 ,import java.io.*; import .*; public class ServerThread extends Thread Socket socket=null; /保存与本线程相关的Socket对象 int clientnum; /保存本进程的客户计数 public ServerThread(Socket socket,int num) /构造函数 this.socket=socket; /初始化socket变量 clientnum=num+1; /初始化clientnum变量 public void run() /线程主体 try Stri
44、ng line; BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream(); /由Socket对象得到输入流,并构造相应的BufferedReader对象 PrintWriter os=newPrintWriter(socket.getOutputStream(); /由Socket对象得到输出流,并构造PrintWriter对象 BufferedReader sin=new BufferedReader(new InputStreamReader(System.in); /由系统标准输
45、入设备构造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); /在系统标准输出上打印该字符串
46、 System.out.println(“Client-“+ clientnum +“:“ +is.readLine(); /从Client读入一字符串,并打印到标准输出上 line=sin.readLine(); /从系统标准输入读入一字符串 /继续循环 os.close(); /关闭Socket输出流 is.close(); /关闭Socket输入流 socket.close(); /关闭Socket server.close(); /关闭ServerSocket catch(Exception e) System.out.println(“Error:“+e); /出错,打印出错信息 ,
47、import java.io.*; import .*; import ServerThread; public class MultiTalkServer static int clientnum=0; /静态成员变量,记录当前客户的个数 public static void main(String args) throws IOException ServerSocket serverSocket=null; boolean listening=true; try serverSocket=new ServerSocket(4700); System.out.println(“Server
48、 is running.”);/创建一个ServerSocket在端口4700监听客户请求 catch(IOException e) System.out.println(“Could not listen on port:4700.”); /出错,打印出错信息 System.exit(-1); /退出 while(listening) /永远循环监听 new ServerThread(serverSocket.accept(),clientnum).start(); /监听到客户请求,根据得到的Socket对象和 客户计数创建服务线程,并启动之 System.out.println(“Client-“+(clientnum+1)+“ is connected.“);clientnum+; /增加客户计数 serverSocket.close(); /关闭ServerSocket ,