790 likes | 926 Views
第 8 章 Java 的网络编程. (时间: 3 次课, 6 学时). 第 8 章 Java 的网络编程. 教学提示: Java 语言已成为网络应用软件开发的主要工具。使用 Java 语言进行网络连接编程比 C++ 语言要容易得多。 Java 提供了许多内置的网络功能,使开发基于 Internet 和 Web 的应用程序更容易。 本章主要介绍: 网络基础知识、 Socket 套接字、 Java 开发 TCP/IP 程序、多线程服务器、数据报、 URL 资源. 第 8 章 Java 的网络编程. 8.1 网络基础知识 8.2 Socket 套接字
E N D
第8章 Java的网络编程 (时间:3次课,6学时)
第8章 Java的网络编程 • 教学提示:Java语言已成为网络应用软件开发的主要工具。使用Java语言进行网络连接编程比C++语言要容易得多。Java提供了许多内置的网络功能,使开发基于Internet和Web的应用程序更容易。 • 本章主要介绍:网络基础知识、Socket套接字、Java开发TCP/IP程序、多线程服务器、数据报、URL资源
第8章 Java的网络编程 • 8.1 网络基础知识 • 8.2 Socket套接字 • 8.3 Java开发TCP/IP程序 • 8.4 多线程服务器 • 8.5 数据报 • 8.6 URL资源 • 8.7 网络聊天程序实例 • 8.8 课后练习
8.1 网络基础知识 • 8.1.1 TCP/lP参考模型 • 8.1.2 建立网络连接
8.1 网络基础知识 • 网络编程涉及客户与服务器两个方面及它们之间的联系。客户端请求服务器执行某个操作,服务器执行这个操作并对客户端作出响应。在网页浏览器与http 服务器之间,按照请求应答响应模式工作。当用户在浏览器中选定一个网站时,这个请求就发送到相应的网络服务器上。服务器发送相应的HTML网页来响应客户端。
8.1.1 TCP/lP参考模型 • TCP/IP是传输控制协议/网际协议的简称,它包含100多个不同功能的协议,是互联网上的通信规则。其中最主要的是TCP 和IP协议。TCP/IP是一个四层的体系结构,它包含应用层、传输层、网际层和网络接口层。
8.1.1 TCP/lP参考模型 • 按照网络通信的不同层次,Java提供的网络功能有4大类:URL、Sockets、Datagram和InetAddress。应用层负责将网络传输的信息转换成我们能够识别的信息,包括很多面向应用的协议,如SMTP(简单邮件传输协议)、HTTP(超文本传输协议)等。在这一层,Java使用URL、URLConnection 类。通过URL 类,Java程序可以直接发出或读取网络上的数据。传输层提供端到端的通信,包括面向连接的TCP(传输控制协议)和无连接的UDP(用户数据包协议)。TCP协议提供了可靠的数据传输服务,具有流量控制、拥塞控制、按顺序递交等功能。UDP增加的服务是不可靠的,但其系统资源开销小,在流媒体系统中使用较多。
8.1.2 建立网络连接 • TCP/IP 中的端口号是一个16 位的数字,它的范围是0~65535。其中的0~1023为系统所保留,专门用于那些通用的服务(例如TELNET、SMTP 和FTP 等),如HTTP 服务的端口号为80,TELNET服务的端口号为21,FTP 服务的端口号为23。因此,编写通信程序时,应选择一个大于1023 的数作为端口号,以免发生冲突。IP地址与端口号组合可以完全分辨Internet 上某台计算机运行的某一程序。 • 客户和服务器必须事先约定所使用的端口。如果系统两部分所使用的端口不一致,则不能进行通信。客户端与服务器端建立连接的过程如图8-2 所示。
8.1.2 建立网络连接 • 图8-2 客户端与网络的连接过程
8.1.2 建立网络连接 • 服务器端软件在远程计算机上连续不断地运行,监听各端口上的通信请求。当服务器上接收到一个对某一端口的连接请求时,就唤醒正在运行的服务器软件,建立连接。该连接将一直保持下去,直到通信的某一方将它中断。
8.2 Socket套接字 • Socket(套接字)是网络上运行的两个程序之间双向通信链路的终端点,它是TCP和UDP的基础。一个Socket 被绑定到一个端口号上,这样传输层就能识别数据要发送哪个应用程序。 • 建立网络连接之后,使用与Socket 相关联的流和使用其他流非常相似。基于Socket的通信通过Socket 读取和写入数据,使应用程序对网上数据的读写操作,像对本地文件的读写一样简单。Socket 允许程序把网络连接当成一个流,可以向这个流写字节,也可以从这个流读取字节。
8.2 Socket套接字 • Java 提供了Stream Sockets(流套接字)和Datagram Sockets(数据报套接字)。用Stream Sockets 可以在两个进程之间建立一个连接,连接建立后,数据在相互连接的进程间流动。所以说Stream Sockets 提供面向连接的服务,它使用的是TCP 协议。 • 在Java编程语言中,TCP/IP Socket 连接是用java.net包中的类实现的。图8-3 说明了Socket 连接机制。
8.2 Socket套接字 • 图8-3 Socket连接机制
8.2 Socket套接字 • Socket工程的通信过程如下。 • (1) 建立连接:服务器端程序分配一个端口号,开始监听来自客户端的请求。当客户请求一个连接时,服务器使用accept()方法打开Socket 连接,将该Socket 连接到此端口上。 • (2) 数据通信:服务器和客户端使用Socket 的InputStream(输入流)和OutputStream(输出流)进行通信。 • (3) 关闭连接:通信结束,服务器和客户端程序断开连接,释放所占用的系统资源。
8.3 Java开发TCP/IP程序 • Java所提供的网络功能可大致分为如下4大类。 • InetAddress:在网络层,用于标识网络上的硬件资源。 • URL 和URLConnection:可表示和建立确定网络上资源的位置,Java程序可以直接读入网络上的数据,或把自己的数据传送到网络的另一端。 • Socket:是两个不同的程序之间在网络上传输数据的通道,这是网络程序中最基本的方法。一般在TCP/IP协议下的客户服务器软件采用Socket 作为交互方式。 • Datagram:是功能最低级的一种。其他网络数据传送方式,都假想在程序执行时,建立一条安全稳定的通道。但是以Datagram 方式传送数据时,只把数据目的地记录在数据包中,然后就直接放在网络上进行传输,系统不保证数据一定能够安全送到,也不能确定什么时候可以送到。
8.4 多线程服务器 • 8.4.1 服务器端ServerSocket • 8.4.2 客户端Socket • 8.4.3 多线程服务器实例
8.4 多线程服务器 • Java软件包内在支持的网络协议为TCP/IP,也是当今最流行的广域网/局域网协议。Java有关网络的类及接口定义在java.net包中。客户端软件通常使用java.net包中的核心类Socket与服务器的某个端口建立连接,而服务器程序不同于客户机,它需要初始化一个端口进行监听,遇到连接呼叫,才与相应的客户机建立连接。
8.4.1 服务器端ServerSocket • 在ServerSocket 类中包含了创建ServerSocket 对象的构造方法、在指定端口监听的方法、建立连接后发送和接收数据的方法。 • 构造方法如下: • public ServerSocket(int port) throws IOException BindExceptio • public ServerSocket(int port, int queuelength) throws IOException, BindException • public ServerSocket(int port, int queuelength, InetAddress bindaddress) throws IOException, BindException
8.4.1 服务器端ServerSocket • ServerSocket 类的常用方法有以下几个。 • public Socket accept() throws IOException • public void close() throws IOException • public InetAddress get InetAddress() • public int getLocalPort()
8.4.2 客户端Socket • 客户端Socket的构造函数如下。 • (1) public Socket(String host,int port) throws unknownHostException, IOException • 这个方法建立一个到主机host、端口号为port 的套接字,连接到远程主机。示范代码如下。 • try • { • Socket soc=new Socket("www.sun.com",80); • //发送数据 • } • catch(unknownHostException uex) • { • } • catch(IOException e) • { • } • (2) public Socket(InetAddress host,int port) throws IOException • 建立一个套接字,与前一个不同的是,它用InetAddress 对象指定套接字。如果出错则抛出IOException 异常。
8.4.2 客户端Socket • Socket类的常用方法有以下几个。 • (1) public InetAddress getInetAddress() • 调用Socket 对象的getInetAddress()方法返回连接到远程主机的地址,如果连接失败,则返回以前连接的主机。 • (2) public int getPort() • 返回Socket连接的远程主机端口号。 • (3) public int getLocalPort() • 一个Socket 连接两个终端,方法getLocalPort()返回本地连接终端的端口号。
8.4.2 客户端Socket • (4) public InetAddress getLocalAddress() • 此方法告诉用户套接字Socket 绑定到哪个网络接口。用户通常在多目录的主机或带有多目录的网络接口上使用这个方法。 • (5) public InputStream getInputStream() throws IOException • 这个方法返回一个输入流,利用这个流就可以从套接字读取数据。通常连接这个流到一个BufferedInputStream 或者BufferedReader。
8.4.2 客户端Socket • (6) public OutputStream getOutputStream() throws IOException • 返回一个原始的Outputstream,可以从应用程序写数据到套接字的另一端。通常将它连接到DataOutputStream 或者OutputStreamWriter 等更方便的类,还可以连接到缓冲类。 • (7) public synchronized void close() throws IOException • 虽然套接字会在程序结束时被自动关闭,但是应该用close()方法断开连接,特别是要运行无限长时间的程序时。
8.4.3 多线程服务器实例 • 【例8.1】下面进行客户机/服务器模式下的Socket 编程,包括一个服务器和一个客户机的程序例子。服务器端程序负责监听客户机请求,为每个客户机请求建立Socket 连接,从而为客户机提供服务。本程序提供的服务为:读取来自客户机的命令,根据客户机的命令,决定服务器要发给客户机的信息,并发送给客户机。
8.4.3 多线程服务器实例 • (1) TCP/IP 服务器ServerSocket • // ==================== Program Discription ======================== • // 程序名称: SimpleServer.java • // 程序目的:TCP/IP服务器应用程序依靠Java技术语言提供的网络类。ServerSocket类 • // 完成建立一个服务器所需的大部分工作。在本机端口5432提供时间服务 • //============================================================= • import java.io.*; • import java.util.*; • import java.net.*; • public class SimpleServer • { • public static void main(String args[]) • {
8.4.3 多线程服务器实例 • ServerSocket s = null; • Socket s1; • OutputStream s1out; • DataOutputStream dos; • //String line="only one line."; • try • { • s = new ServerSocket(5432); • // Register your service on port 5432 • } • catch (IOException e) {}// Run the listen/accept loop forever • while (true) • { • try • {
8.4.3 多线程服务器实例 • s1 = s.accept();// Wait here and listen for a connection • s1out = s1.getOutputStream(); • // Get a communication stream for soocket • dos = new DataOutputStream(s1out); • dos.writeUTF(new Date().toString()); • // Send string!(UTF provides machine-independent format) • //dos.writeUTF(line); • s1out.close(); • // Close the connection, but not the server socket • s1.close(); • } • catch (IOException e) {} • } • } • }
8.4.3 多线程服务器实例 • (2) 客户端Socket • // ==================== Program Discription ========================= • // 程序名称: SimpleClient.java • // 程序目的:客户端Socket完成了建立一个连接所需的大部分工作。客户连接到服务器上,显 • // 示服务器发送的所有时间数据。通过Socket获得服务器提供的时间字符串,并显示 • //============================================================= • import java.net.*; • import java.io.*; • public class SimpleClient • { • public static void main(String args[]) throws IOException • { • Socket s1; • InputStream s1In; • DataInputStream dis; • String st;
8.4.3 多线程服务器实例 • s1 = new Socket("127.0.0.1",5432); • //Open your connection to sunbert, at port 5432 • s1In = s1.getInputStream(); • //Get an inputStream from the socket and read the input • dis = new DataInputStream(s1In); • st = new String (dis.readUTF()); • System.out.println(st); • // When done, just close the connection and exit • s1In.close(); • s1.close(); • } • } • 运行结果如图8-4所示。
8.4.3 多线程服务器实例 • 图8-4 运行结果(例8.1)
8.5 数据报 • 8.5.1 DatagramPacket • 8.5.2 DatagramSocket • 8.5.3 数据报实例 • 8.5.4 组播套接字 MulticastSocket
8.5 数据报 • TCP/IP是一种面向连接的协议,而用UDP 是一种无连接的协议,它只是把数据的目的地记录在数据报中,然后直接放在网络上,不保证传送质量。 • 在java.net包中有3个类支持基于UDP协议的网络通信: • 表示数据报的DatagramSocket类; • 用于端到端通信的DatagramPacket类; • 用于广播通信的MulticastSocket类。
8.5.1 DatagramPacket • 1. 将数据打包 • java.net包中的DatagramPacket类用来创建数据报。数据报有两种,一种用来传递数据报,该数据报有要传递到的目的地址;另一种数据报用来接收传递过来的数据报中的数据。分别用DatagramPacket 的两个构造函数来创建。 • (1) DatagramPacket(byte[] recvBuf, int readLength) • 用来建立一个字节数组以接收UDP包。byte 数组在传递给构造函数时是空的,而int 值用来设置要读取的字节数(不能比数组的大小还大)。
8.5.1 DatagramPacket • (2) DatagramPacket(byte[] sendBuf, int sendLength, InetAddress iaddr, int iport) • 用来建立将要传输的UDP包。sendLength不应该比sendBuf字节数组的大小还大。如果数据报长度超出length,则触发IllegalArgument Exception。不过这时RuntimeException不需要用户代码捕获。 • 2. 使用数据报 • 通过接收数据报对象,获取数据报中的信息的方法有以下几个。 • (1) public InetAddress getAddress() • 如果是发送数据报,则获得数据报要发送的目标地址,但是如果是接收数据报,则返回发送此数据报的源地址。
8.5.1 DatagramPacket • (2) public byte[]getData() • 返回一个字节数组,其中是数据报的数据。如果想把字节数组转换成其他类型,就要进行转化。 • (3) public int getLength() • 获得数据报中数据的字节数。 • (4) pubic int getPort() • 返回数据报中的目标地址的主机端口号。通过发送数据报对象设置发送数据报中的信息的方法有:setAddress(InetAddress iaddr)、setPort(int iport)、setData(byte[] buf)、setData(byte[] buf, int offset, int length)、setLength(intlength)。详细资料可查Java文档。
8.5.2 DatagramSocket • 发送和接收数据报还需要发送和接收数据报的Socket,即DatagramSocket 对象。DatagramSocket 用来读写UDP 包。它在本地机器端口监听是否有数据到达或者将数据报发送出去。DatagramSocket 类有3 个构造函数,允许指定要绑定的端口号和Internet 地址。 • (1) public DatagramSocket() • 用本地机上任何一个可用的端口创建一个套接字,这个端口号是由系统随机产生的。使用方法如下。 • try • { • DatagramSocket datas=new DatagramSocket(); • //发送数据报 • } • catch(SocketException e) • { • //异常处理 • }
8.5.2 DatagramSocket • 这种构造方法没有指定端口号,可以用在客户端。如果构造不成功则触发SocketException 异常。 • (2) public DatagramSocket(int port) • 用一个指定的端口号port 创建一个套接字。当不能创建套接字时就抛出SocketException 异常,其原因是指定的端口已被占用或者是试图连接低于1024 的端口,但是又没有权限。 • (3) DatagramSocket(int port, InetAddress iaddr) • 绑定指定地址的指定端口。
8.5.3 数据报实例 • 【例8.2】基于UDP 的服务器/客户端通信程序。 • (1) 创建UDP服务器 • // ==================== Program Discription ======================= • // 程序名称:UDPServer.java • // 程序目的:UDP服务器在8000端口监听客户的请求。当它从客户接收到一个 • // DatagramPacket时,它发送服务器上的当前时间 • //================================================================= • import java.io.*; • import java.net.*; • import java.util.*; • public class UDPServer • { • //This method retrieves the current time on the server • public byte[] getTime() • {
8.5.3 数据报实例 • Date d= new Date(); • return d.toString().getBytes(); • } • // Main server loop. • public void go() throws IOException • { • DatagramSocket datagramSocket; • DatagramPacket inDataPacket; // Datagram packet from the client • DatagramPacket outDataPacket; // Datagram packet to the client • InetAddress clientAddress; // Client return address • int clientPort; // Client return port • byte[] msg= new byte[10]; // Incoming data buffer. Ignored. • byte[] time; // Stores retrieved time • // Allocate a socket to man port 8000 for requests. • datagramSocket = new DatagramSocket(8000); • System.out.println("!!!!!!at UDPServer,datagramSocket is: " + • datagramSocket.getPort() + "local is: " + datagramSocket.getLocalPort()); • System.out.println("UDP server active on port 8000"); • // Loop forever • while(true)
8.5.3 数据报实例 • { • // Set up receiver packet. Data will be ignored. • inDataPacket = new DatagramPacket(msg, msg.length); • // Get the message. • datagramSocket.receive(inDataPacket); • // Retrieve return address information, including InetAddress • // and port from the datagram packet just recieved. • clientAddress = inDataPacket.getAddress(); • clientPort = inDataPacket.getPort(); • // Get the current time. • time = getTime(); • //set up a datagram to be sent to the client using the • //current time, the client address and port • outDataPacket = new DatagramPacket • (time, time.length, clientAddress, clientPort); • //finally send the packet • datagramSocket.send(outDataPacket); • } • }
8.5.3 数据报实例 • public static void main(String args[]) • { • UDPServer udpServer = new UDPServer(); • try • { • udpServer.go(); • } catch (IOException e) { • System.out.println("IOException occured with socket."); • System.out.println(e); • System.exit(1); • } • } • } • 运行结果如图8-5所示。
8.5.3 数据报实例 • 图8-5 运行结果(例8.2(1))
8.5.3 数据报实例 • (2) UDP 客户端 • // ==================== Program Discription ======================= • // 程序名称:UDPClient.java • // 程序目的:UDP客户向前面创建的客户发送一个空包并接收一个包含服务器实际时间的包 • // ================================================================ • import java.io.*; • import java.net.*; • class UDPClient • { • public void go() throws IOException, UnknownHostException • { • DatagramSocket datagramSocket; • DatagramPacket outDataPacket; // Datagram packet to the server • DatagramPacket inDataPacket; // Datagram packet from the server • InetAddress serverAddress; // Server host address • byte[] msg = new byte[100]; // Buffer space.
8.5.3 数据报实例 • String receivedMsg; // Received message in String form. • // Allocate a socket by which messages are sent and received. • datagramSocket = new DatagramSocket(); • System.out.println("!!!!!!at UDPClient,datagramSocket is: " + • datagramSocket.getPort() + "local port is: " • +datagramSocket.getLocalPort()); • // Server is running on this same machine for this example. • // This method can throw an UnknownHostException. • serverAddress = InetAddress.getLocalHost(); • // Set up a datagram request to be sent to the server. • // Send to port 8000. • outDataPacket = new DatagramPacket(msg, 1, serverAddress, 8000); • // Make the request to the server. • datagramSocket.send(outDataPacket); • // Set up a datagram packet to receive server's response. • inDataPacket = new DatagramPacket(msg, msg.length); • // Receive the time data from the server • datagramSocket.receive(inDataPacket); • // Print the data received from the server
8.5.3 数据报实例 • receivedMsg = new String • (inDataPacket.getData(), 0, inDataPacket.getLength()); • System.out.println(receivedMsg); • //close the socket • datagramSocket.close(); • } • public static void main(String args[]) • { • UDPClient udpClient = new UDPClient(); • try { • udpClient.go(); • } catch (Exception e) • { • System.out.println ("Exception occured with socket."); • System.out.println (e); • System.exit(1); • } • } • } • 运行结果如图8-6所示。
8.5.3 数据报实例 • 图8-6 运行结果(例8.2(2))
8.5.4 组播套接字 MulticastSocket • DatagramSocket只允许数据报发往一个目的地址。java.net类包中提供了类MulticastSocket,允许将数据报以广播的方式发送到某个端口的所有客户。MulticastSocket 类是DatagramSocket类的子类。它在客户端(接收端)使用,监听服务器端广播来的数据;而服务器端仍然使用DatagramSocket来发送数据,只是发送的数据报的目的地址有所变化。其构造方法如下。 • public MulticastSocket() • public MulticastSocket(int port):在指定的端口通信。
8.5.4 组播套接字 MulticastSocket • 这两个方法都将抛出异常IOException,在程序中需要捕获处理。MulticastSocket类的主要方法如下。 • public void joinGroup(InetAddress mcastaddr):加入一个广播组。 • public void leaveGroup(InetAddress mcastaddr):离开一个广播组。 • public void setTimeToLive(int ttl):指定数据报发送时间。 • public void send(DatagramPacket p, byte ttl):在指定的时间内将数据报发送出去。
8.6 URL资源 • 8.6.1 InetAddress 类 • 8.6.2 URL和URLConnection
8.6 URL资源 • 连接到网络中的每台计算机(或其他设备)都有惟一的地址,这就是IP 地址。java.net.InetAddress 类是Java的IP地址封装类,它不需要用户了解如何实现对IP 地址操作的细节。 • 在互联网上,以URL(统一资源定位器)表示Internet上各种数据资源的地址。为了处理方便,Java将URL 封装成URL 类,可以用一个URL 对象记录下完整的URL 信息。