700 likes | 881 Views
Chapter 11 : Java 网络编程. 授课教师:赵小敏 浙江工业大学 软件学院 Email:zxm@zjut.edu.cn. 主要内容. 1 、 网络基础知识 2 、 Socket 和 ServerSocket 类 3 、基于 TCP 的 Java 编程 4 、基于 UDP 的 Java 编程 5 、基于 URL 类的 Java 网络编程. 1 、 网络基础知识. 计算机网络形式多样,内容繁杂。网络上的计算机要互相通信,必须遵循一定的协议。目前使用最广泛的网络协议是 Internet 上所使用的 TCP/IP 协议
E N D
Chapter 11:Java网络编程 授课教师:赵小敏 浙江工业大学 软件学院 Email:zxm@zjut.edu.cn
主要内容 • 1、 网络基础知识 • 2、Socket和ServerSocket类 • 3、基于TCP的Java编程 • 4、基于UDP的Java编程 • 5 、基于URL类的Java网络编程
1、 网络基础知识 • 计算机网络形式多样,内容繁杂。网络上的计算机要互相通信,必须遵循一定的协议。目前使用最广泛的网络协议是Internet上所使用的TCP/IP协议 • 网络编程是指利用不同层次的通信协议提供的接口实现网络进程通信的编程。 • 网络编程中有两个主要的问题,一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输。在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一地确定Internet上的一台主机。而TCP层则提供面向应用的可靠的或非可靠的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据的。
1、网络基础知识(续2) • 目前较为流行的网络编程模型是客户机/服务器(C/S)结构。即通信双方一方作为服务器等待客户提出请求并予以响应。客户则在需要服务时向服务器提出申请。服务器一般作为守护进程始终运行,监听网络端口,一旦有客户请求,就会启动一个服务进程来响应该客户,同时自己继续监听服务端口,使后来的客户也能及时得到服务。
1、网络基础知识(续3) • 网络进程是指在网络结点计算机上运行的程序 • 通信协议指网络进程之间的通信必须遵循预定的规则。 • TCP/IP是一组在Internet网络上的不同计算机之间进行通信的协议的总称,它由应用层的HTTP、FTP、SMTP和传输层的TCP及网络层的IP等一系列协议组成。
TCP/UDP/IP • TCP(传输控制协议)是面向连接的、可靠的点对点的传输协议。 • UDP(用户数据报协议)是无连接的不可可靠的传输协议。 • IP是网络层协议,实现按IP地址的网络路由的功能。
TCP • 通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。
UDP UDP是User Datagram Protocol的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。
套接字 • “套接字”或者“插座”(Socket)也是一种软件形式的抽象,用于表达两台机器间一个连接的“终端”。 • 针对一个特定的连接,每台机器上都有一个“套接字”,可以想象它们之间有一条虚拟的“线缆”。线缆的每一端都插入一个“套接字”或者“插座”里。 • 进程之间要实现通信首先要建立各自的套接字。 • 在Java中,我们创建一个套接字,用它建立与其他机器的连接。
TCP/IP中的端口号 • 机器内独一无二的场所有些时候,一个IP地址并不足以完整标识一个服务器。这是由于在一台物理性的机器中,往往运行着多个服务器(程序)。由IP表达的每台机器也包含了“端口”(Port)。 • TCP/IP系统中的端口号是16位的数字,从0 ~65535。一般<=1023由预先定义的服务占用,如telnet,SMTP mail、ftp等。 • Client 与Server在建立连接前,必须事先约定号端口号。
Java网络程序设计支持机制 Java网络应用系统 支持URL的类 • 利用URL访问网络资源 • 利用Socket通信 支持Socket通信的类 网 络
Java网络程序设计支持机制 • 支持网络通信的类在java.net包中。 • URL, URLConnection, Socket, ServerSocket ,使用TCP实现网络通信。 • DatagramPacket, DatagramSocket, MulticastSocket 支持 UDP 通信方式。
2、 Socket和ServerSocket类 • 客户套接字类(Socket) • 服务器套接字类(ServerSocket)
套接字类Socket 1、 Socket的四种构造方法 (1) Socket(String host,int port) thows UnknownHostException,IOException 创建一个面向连接的套接字对象,并将其连接至特定的主机(host)的特定端口(port) (2) Socket(String host,int port,boolean stream) 创建一个套接字对象,并将其连接至特定的主机的特定端口上,此套接字对象是面向连接的还是数据报的,则由最后的一个参数决定
套接字类Socket 1、 Socket的四种构造方法 (3) Socket(InetAddress address,int port) 创建一个面向连接的套接字对象,并将其连接至特定IP的主机的特定端口(port) (4) Socket( InetAddress address ,int port,boolean stream) 创建一个套接字对象,并将其连接至特定ip主机的特定端口上,此套接字对象是面向连接的还是数据报的,则由最后的一个参数决定
套接字类Socket 2、 Socket提供的主要方法 (1) InetAddress getInetAddress() 返回该套接字所连接的IP地址 (2) Int getPort() 返回该套接字所连接的远程端口 (3) sychronized void close() throws IOException 关闭套接字
套接字类Socket 2、 Socket提供的主要方法 (4) InputStream getInputStream () throws IOException 获得套接字绑定的数据的输入流 (5) PrintStream getOutputStream() throws IOException 获得向套接字绑定的数据输出流
服务器套接字(ServerSocket) 1、ServerSocket类的构造方法 (1) ServerSocket(int port) throws IOException 构造一个ServerSocket对象,其绑定的端口号为port (2) ServerSocket(int port , int count) 构造一个ServerSocket对象,其绑定的端口号为port,如port为0,则该对象与缺省的端口号绑定。其中count为该对象端口上等待的连接的客户最大数
服务器套接字(ServerSocket) 2、ServerSocket类的主要方法 (1) Socket accept() throws IOException 等待客户连接,该方法将阻塞当前系统服务线程,直到连接成功。该方法返回一个套接字类对象,通过该套接字,新的服务子线程与连接的客户进行通信。 (2) Void close() throws IOException 关闭套接字
怎样用socket进行客户与服务器通信 Socket是两个实体之间进行通信的有效端点。通过socket可以获得源IP地址和源端口、终点IP地址和终点端口。用户可以将多个socket连入同一个端口,以便对于单个端口可以有多个连接。 通过socket客户/服务器编程可以创建一个能被许多人使用的分布式程序,并且所有客户均可以用统一的前端进行工作,并与服务器进行通信。
与服务器通信必须具备三个条件 • 服务器程序 • 客户程序 • 连接它们的socket程序
ServerSocket类 • 它的实例使服务器能够检测到指定端口的信息 • accept()方法可以使服务器检测到指定端口的活动 • 服务器还负责检测要求与它连接的客户。
Socket类 • getInputStream()和getOutStream()方法来发送和捕捉数据。 try{ //传递给它一个整数作为服务器指定可以使用的给定端口 ServerSocket myServerSocket=new ServerSocket(100); Socket my100Socket=myServerSocket.accept(); //检测端口的活动 }catch(Exception e){}
Socket类 Accept()方法直到接收到用户的连接请求,才继续执行中断的执行程序。一旦客户的连接成功,my100Socket就代表该连接,并且可以发送和接收数据。 最后,我们看一看客户是怎样请求连接的。其连接方法如下: try{ Socket mySocket=new Socket("www.cpcw.com",100); }catch(Exception e ){}
3、基于TCP的Java网络编程 • 一对一的Socket C/S通信 TCP是面向连接的、可靠的网络传输协议,当两个网络进程准备进行通信时,都必须首先建立各自的一个套接字,其中服务器建立套接字后,侦听来自网络的客户连接请求,客户通过套接字,指定服务器的IP地址和端口号,便可与服务器进行通信。
(一)TCP协议通信的服务器方实现 (1) 假设服务器工作在端口8000上, ServerSocket svrsoc= ServerSocket(8000) Socket soc=svrsoc.accept();//监视端口8000的连接请求 (2) 打开与soc绑定的输入/输出流: In=new BufferedReader(new InputStreamRead(soc.getInputStream())); //在套接字soc上绑定的输入流基础上构造BufferedReader对象
(一) TCP协议通信的服务器方实现(续) out=new PrintWrite(new bufferedWrite(new OutputStreamWrite(soc.getOutputStream())),true); //在套接字soc上绑定的输出流基础上构造PrintWrite对象 服务器使用in和out两个实例从客户接收输入信息和向客户程序发信息,同样,在客户端也应该建立这两个对象,用来与服务器程序进行双向通信。
(一) TCP协议通信的服务器方实现(续) (3) 获取客户机的IP地址,并在服务器窗口中显示客户机的地址信息: clientIP=soc.getInetAddress(); System.out.println(“Client’s IP address:”+clientIP);
(一) TCP协议通信的服务器方实现(续) (4) 读入一行客户的输入,并回显该行 String str=in.readLine(); while(!str.equals(“quit”));{ System.out.println(“Client said:”+str); str=in.readLine(); }
(一) TCP协议通信的服务器方实现(续) (5) 不断循环以上代码,直到客户输入“quit”为止。 System.out.println(“Client want to leave.”); finall{ in.close(); out.close(); soc.close(); svrsoc.close(); }
(二)TCP协议通信的客户方实现 (1)创建一个指向固定主机的固定端口的Socket: Socket soc=new Socket(“localhost”,8000); (2) 从Socket对象中获取与其绑定的输入和输出流 In=new BufferedReader(new InputStreamRead(soc.getInputStream())); out=new PrintWrite(new bufferedWrite(new OutputStreamWrite(soc.getOutputStream())),true);
(二)TCP协议通信的客户方实现(续) (3)建立输入/输出流后,从服务器读取发来的”welcome!”信息,显示在窗口: Strin=in.readLine(); System.out.println(“Server said:”+strin);
(二)TCP协议通信的客户方实现(续) (4)客户向服务器发送的数据流从键盘获取 byte bmsg[]=new byte[200]; System.in.read(bmsg); //从键盘读入bmsg String msg=new String(bmsg,0); //byte型转String型 Msg=msg.trim(); //删除msg两边的空格
(二)TCP协议通信的客户方实现(续) (5)当键盘输入不是“quit”时,将键盘输入的数据写入输出流中,并发送出去,然后继续从键盘获取输入数据,不断循环,直到输入“quit”时,先将其传送给服务器,然后关闭输入/输出流和Socket: out.println(strout); In.close(); out.close(); soc.close(); System.exit(0);
一个简单的客户端/服务器程序 • import java.net.*; • 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 DIS; • 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 DataInputStream(System.in); • while(true){ • System.out.println(""); • System.out.println("please wait client's 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("BYE"))break; • } • DIS.close(); • PS.close(); • Is.close(); • Os.close(); • socket.close(); • } catch(Exception e){ • System.out.println("Error:"+e); • } //catch • } //main • } //public class
import java.net.*; • import java.io.*; • import java.lang.*; • public class myclient{ • public static void main(String args[]){ • if (args.length<1){ • System.out.println("Please input the Server Name or IP!"); • System.out.println("see also: myclient 127.0.0.1"); • System.exit(1); } //if • Socket socket; • String s=“zxm@zjut.edu.cn"; • String len; • InputStream Is; • OutputStream Os; • DataInputStream DIS; • PrintStream PS; • try{ • socket=new Socket(args[0],4321); • System.out.println("client ok"); • System.out.println("************************************************"); • 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; // • else • { • System.out.println(""); • System.out.println("please wait server's 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.println("Error:"+e); • } • } • }
(三)支持多客户的client/server程序设计 • 在实际应用中,往往是在服务器上运行一个永久的程序,它可以接收来自其他多个客户端的请求,提供相应的服务。为了实现在服务器方给多个客户提供服务的功能,需要对上面的程序进行改造,利用多线程实现多客户机制。服务器总是在指定的端口上监听是否有客户请求,一旦监听到客户请求,服务器就会启动一个专门的服务线程来响应该客户的请求,而服务器本身在启动完线程之后马上又进入监听状态,等待下一个客户的到来。
import java.io.*; import java.net.*; public class TalkClient {public 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对象 BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));//由Socket对象得到输入流,并构造相应的BufferedReader对象String readline;readline=sin.readLine(); //从系统标准输入读入一字符串while(!readline.equals(“bye”)){ //若从标准输入读入的字符串为 “bye”则停止循环os.println(readline); //将从系统标准输入读入的字符串输出到Serveros.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(Exception e) {System.out.println(“Error”+e); //出错,则打印出错信息}} }
import java.io.*; import java.net.*; 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{String 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));//由系统标准输入设备构造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(); //关闭Socketserver.close(); //关闭ServerSocket}catch(Exception e){System.out.println("Error:"+e); //出错,打印出错信息}}}
import java.io.*; import java.net.*; 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 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}}
4、基于UDP协议的Java网络编程 • 利用TCP协议通信必须首先使客户和服务器之间建立一个专门的通道进行数据交换——效率低 • UDP协议把要发送的数据及对方的IP地址和端口号构成报文(datagram),不与对方连接就把报文一个个独立地发送出去。
Datagram • TCP/IP传输层由两个并列的协议:TCP,UDP. • 一般套接字(TCP)提供一个可靠的传输模型作为两个网络端点的字节流,有纠错能力. • UDP没有保持的连接和数据流,数据报是一个网络上发送的独立信息,它的到达,到达时间,以及内容不能得到保证. socket client server datagram server client
Datagram • TCP提供高可靠性服务,适用于一次要传输交换大量报文的情况,信道上传递的包不需要源地址和目的地址 • UDP提供高效率服务,适用于依次传输交换少量报文的情形 (如数据库查询),每个数据包要包含目的地址和端口号. • 数据报文的使用以包为中心:打包,拆包. • Java.net包支持两种不同的在网络上送数据的方法:一般套接字和数据报文套接字.
Datagram • 发出报文的标准步骤如下: 1. 定义数据成员 DatagramSocket socket; DatagramPacket packet; InetAddress address;(用来存放接收方的地址) int port; ;(用来存放接收方的端口号) 2. 创建数据报文Socket对象 try {socket=new DatagramSocket(1111);} catch(java.net.SocketException e) {} socket 绑定到一个本地的可用端口,等待接收客户的请求.
Datagram 3.分配并填写数据缓冲区(一个字节类型的数组) byte[] Buf=new byte[256]; 存放从客户端接收的请求信息. 4.创建一个DatagramPacket packet=new DatagramPacket(buf, 256); 用来从socket接收数据,它只有两个参数 5. 服务器阻塞 socket.receive(packet); 在客户的请求报道来之前一直等待