网络部分 网络基础理论 InetAddress 类 URL 类 Socket 通信机制 多线程服务器 数据报文通信 广播式通信
计算机网络基础 什么是计算机网络 –把分布在不同地理区域的计算机与专门的外部设备 用通信线路互连成一个规模大、功能强的网络系统 ,从而使众多的计算机可以方便地互相传递信息, 共享硬件、软件、数据信息等资源。
计算机网络的主要功能 –资源共享 –信息传输与集中处理 –均衡负荷与分布处理 –综合信息服务 (www/ 综合业务数字网络 ISDN)
计算机网络分类 按规模大小和延伸范围划分: – 局域网( LAN -- local area network ) – 城域网( MAN-- metropolitan area network ) – 广域网( WAN – wide area network ) 按照网络的拓扑结构划分: – 环形网、星形网、总线型网等 按照通信 传输的介质来划分: – 双绞线网、同轴电缆网、光纤网和卫星网等 按照信号频带占 用方式划分: – 基带网和宽带网
局域网的几种工作模式 专用服务器结构 (Server-Based) 又称为“工作站/文件服务器”结构,由若干台微机工作站 与一台或多台文件服务器通过通信线路连接起来组成工作站 存取服务器文件,共享存储设备。
客户机 / 服务器模式 (client / server) 其中一台或几台较大的计算机集中进行共享数据库的管理和 存取,称为服务器,而将其它的应用处理工作分散到网络中 其它微机上去做,构成分布式的处理系统。
对等式网络:( Peer-to-Peer) 在拓扑结构上与专用 Server 与 C / S 相同。在对等式网络 结构中,没有专用服务器 每一个工作站既可以起客户机作用 也可以起服务器作用。
网络通信协议及接口 什么是网络通信协议 计算机网络中实现通信必须有一些约定即通信协议 ,对速率、传输代码、代码结构、传 输控制步骤 、出错控制等制定标准。
网络通信接口 为了使两个结点之间能进行对话,必须在它们之间 建立通信工具 ( 即接口 ) ,使彼此之间 能进行信 息交换。接口包括两部分: –硬件装置 : 实现结点之间的信息传送 –软件装置 : 规定双方进行通信的约定协议
通信协议分层的思想 为什么要分层 由于结点之间联系很复杂,在制定协议时,把复杂成份分 解成 一些简单的成份,再将它们复合起来。最常用的复 合方式是层次方式,即同层间可以通信、上一层可以调用 下一层,而与再下一层不发生关系。
通信协议的分层规定 把用户应用程序作为最高 层,把物理通信线路作为最低 层,将其间的协议处理分为若干层,规定每层处理的任务 ,也规定每层的接口标准。
通信协议分层演示 主机 A
第 5 层 第 4 层 第 3 层 第 2 层 第 1 层
第 5 层协议 第 4 层协议 第 3 层协议 第 2 层协议 第 1 层协议
物 理 介 质
第 5 层 第 4 层 第 3 层 第 2 层 第 1 层
主机 B
参考模型 OSI 参考模型
TCP/IP 参考模型
应 用 层 表 示 层
应
用
层
传 输 层
传
输
层
网 络 层
网
络
层
会 话 层
数据链路层 物 理 层
物理 + 数据链路层
数据的封装与拆封 • 封装 – 发送方数据在网络模型的各层传送过程中加入 头尾的过程
• 拆封 – 接受方收到数据后去除相应的头尾的过程
TCP/IP 协议 TCP -- Transmission Control Protocol IP -- Internet Protocol TCP/IP 协议可保证不同厂家生产的计算机能在共同网 络环境下运行,解决异构网通信问题, TCP/IP 与低 层的数据链路层和物理层无关,能广泛地支持由低两层 协议构成的物理网络结构。 TCP -- 面向连接的可靠数据传输协议; TCP 重发一切 没有收到的数据,进行数据内容准确性检查并保证分组 的正确顺序。
IP 协议 IP 协议是网际层的主要协议,支持网间互连 的数据报通信。它提供主要功能有: – 无连接数据报传送 – 数据报路由选择和差错控制
IP 协议主要特性: IP 协议将报文传送到目的主机后,无论传送正确与否 都不进行检验、不回送确认、不保证分组的正确顺序 。
IP 地址 TCP/IP 用 IP 地址来标识源地址和目的地址 IP 地址功能:为实现网络中不同计算机之间的通信 ,每台机器都必须有一个与众不同的标识 ---IP 地址 ; IP 地址格式:数字型, 32 位,由 4 个 8 位的二进制 数组成,每 8 位之间用圆点隔开,如: 166.111.78.98 ; IP 地址组成:网络标识 (netId) + 主机标识 (hostId) ; IP 地址分类:分为 A 、 B 、 C 三类,每个类别的网 络标识和主机标识各有规则。
Java 网络编程 • Java 所提供的网络功能可大致分为三大类 – URL 和 URLConnection 这是三大类功能中最高级 的一种。通过 URL 的网络资源表达方式,很容 易确定网络上数据的位置 – Socket ,可以想像成两个不同的程序通过网络 的通道,而这是传统网络程序中最常用的方法 – Datagram 是不可靠方式的连接, Datagram不能 保证传送质量
网络部分 网络基础理论 InetAddress 类 URL 类 Socket 通信机制 多线程服务器 数据报文通信 广播式通信
InetAddress 类 • java.net.InetAddress 类是 Java 的 IP 地址封装类,它 不需要用户了解如何实现地址的细节 • InetAddress 类没有构造方法,要创建该类的实例对 象,可以通过该类的静态方法获得该对象 – public static InetAddress getLocalHost() – public static InetAddress getByName (String host) – public static InetAddress[] getAllByName(String host)
实例 1—— 查寻 IP 地址版本 import java.net.*; import java.io.*; public class IPVersion { public static void main(String args[]) { try { InetAddress inetadd=InetAddress.getLocalHost(); byte[ ] address=inetadd.getAddress( ); if (address.length==4) { System.out.println("The ip version is ipv4"); int firstbyte=address[0]; if (firstbyte<0) firstbyte += 256; if((firstbyte&0x80)==0 ) System.out.println("the ip class is A"); else if ((firstbyte&0xC0)==0x80 ) System.out.println("The ip class is B"); else if((firstbyte&0xE0)==0xC0 ) System.out.println("The ip class is C"); else if((firstbyte&0xF0)==0xE0) System.out.println("The ip class is D"); else if((firstbyte&0xF8)==0xF0 ) System.out.println("The ip class is E"); } else if(address.length==16) System.out.println("The ip version is ipv6"); } 36 catch (Exception e) { };
实例 2—— 取得主机名 import java.net.*; import java.io.*; class Internet { public static void main(String args[]) { try { InetAddress inetadd; inetadd=InetAddress.getLocalHost(); System. out. println ("hostname="+inetadd.getHostName()); System. out. println(inetadd.toString() ); } catch(Exception e) { System.out.println(e); }} }
网络部分 网络基础理论 InetAddress 类 URL 类 Socket 通信机制 多线程服务器 数据报文通信 广播式通信
URL 类 URL(Uniform Resource Locator)---- 统一资源定位器 ,表示 Internet 上某一资源的地址。 URL 组成 : 协议名和资源名 protocol:resourceName
URL 举例 : – http://www.sun.com/ – http://home.netscape.com/home/welcome.html – http://www.sun.com.cn/developers/
java.net .URL 类 常用构造方法 – public URL(String spec); URL u1 = new URL(“http://home.netscape.com/home/”); – public URL(URL context, String spec); URL u2 = new URL(u1, “welcome.html”); – public URL(String protocol, String host, String file); URL u3 = new URL(“http”, “www.sun.com”, “developers/index.html” ); – public URL (String protocol, String host, int port, String file); URL u4 = new URL(“http”, “www.sun.com”, 80, “developers/index.html” );
URL 类中基本方法 • • • • •
public final Obect getContent() 这个方法取得传输协议 public String getFile() 这个方法取得资源的文件名 public String getHost() 这个方法取得机器的名称 public int getPort() 这个方法取得端口号 public String getProtocol() 这个方法取得传输协议
• public String toString() 这个方法把 URL 转化为字符串。
URL 类应用举例 (1) import java.io.*; import java.net.*; public class URLReader{ public static void main(String args[]){ try{ URL tirc = new URL("http://www.tsinghua.edu.cn/"); BufferedReader in = new BufferedReader(new InputStreamReader(tirc.openStream())); String s; while((s = in.readLine())!=null) System.out.println(s); in.close(); }catch(MalformedURLException e) { System.out.println(e); }catch(IOException e){ System.out.println(e); } } }
URL 类应用举例 (2) 程序 URLReader.java 输出结果 :
清华大学网站首页 <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <meta http-equiv="refresh" content="0;URL=./eng/index.htm"> // 如使用了代理服务器,则使用下述命令运行: //java -Dhttp.proxyHost= -Dhttp.proxyPort=<port> URLReader
网络部分 网络基础理论 InetAddress 类 URL 类 Socket 通信机制 多线程服务器 数据报文通信 广播式通信
什么是套节字( Socket ) • 网络接口是实现服务器程序与一个或多个客户程 序之间双向通信的软件端点 • 网络接口使服务器程序与运行该程序的计算机上 特定的硬件端口关联起来,这样 在网络中的任何 位置上,带有与该端口相关联的网络接口的客户 程序都可以与这 个服务器程序实现通信。 • 套节字是用于实现网络上的客户程序与服务器程 序之间的连接,这个连接的端点即称为套节字 – 套节字负责网络上的通信,客户程序可以向套节字里 写入请求,然后服务器会处理这个请求,并把处理结 果通过套节字返回
• 套节字是在较底的层次上进行通信的
Socket 两个 Java 应用程序可通过一个双向的网络通信连 接实现数据交换,这个双向链路的一端称为一个 socket 。 socket 通常用来实现 client-server 连接。 java.net 包中定义的两个类 Socket 和 ServerSocket , 分别用来实现双向连接的 client 和 server 端 建立连接时所需的寻址信息 – 远程计算机的机器名或 IP 地址 – 试图连接的端口号 (Port number)
套节字工作原理 • 服务器程序对某个特定的端口监听 • 客户端对服务器端进行连接请求 • 建立连接,客户端被分配一个本地端口号 与一个 socket 连接 • 客户端与服务器端通过 socket 套节字进行交 流
Socket 通信模型 Server
Client
ServerSocket s (port #) s.accept()/ 等待连接 Socket() OutputStream InputStream socket.close()
Socket (host, port #) ( Attempt to connect ) OutputStream InputStream socket.close()
网络编程的四个基本步骤 1. 创建 socket; 2. 打开连接到 socket 的输入 / 输出流; 3. 按照一定的协议对 socket 进行读 / 写操作 ; 4. 关闭 socket;
创建 socket Socket/ServerSocket 类的构造方法 Socket(InetAddress address, int port); Socket(InetAddress address, int port, boolean stream); Socket(String host, int port); Socket(String host, int port, boolean stream); ServerSocket(int port); ServerSocket(int port, int count);
客户端 Socket 的建立 try{ Socket socket=new Socket(”127.0.0.1",2000); }catch(IOException e){ System.out.println("Error:"+e); }
服务器端 Socket 的建立 ServerSocket server=null; try { server=new ServerSocket(2000); }catch(IOException e){ System.out.println("can not listen to :"+e); } Socket socket=null; try { socket=server.accept(); }catch(IOException e){ System.out.println("Error:"+e); }
打开输入 / 出流 PrintStream os=new PrintStream(new BufferedOutputStream (socket.getOutputStream())); DataInputStream is=new DataInputStream(socket.getInputStream());
关闭 Socket os.close(); is.close(); socket.close();
简单的 client/server 程序 import java.net.*; import java.io.*; public class TestServer { public static void main(String args[]) { try { ServerSocket s = new ServerSocket(8888); while (true) { Socket s1 = s.accept(); OutputStream os = s1.getOutputStream(); DataOutputStream dos = new DataOutputStream(os); dos.writeUTF("Hello," + s1.getInetAddress() + "port#" +s1.getPort() + " bye-bye!"); dos.close(); s1.close(); } }catch (IOException e) { System.out.println(" 出错 :" + e);} } }
简单的 client/server 程序 import java.net.*; import java.io.*; public class TestClient { public static void main(String args[]) { try { Socket s1 = new Socket("127.0.0.1", 8888); InputStream is = s1.getInputStream(); DataInputStream dis = new DataInputStream(is); System.out.println(dis.readUTF()); dis.close(); s1.close(); } catch (ConnectException connExc) { System.err.println(" 服务器连接失败! "); } catch (IOException e) { } } }
网络部分 网络基础理论 InetAddress 类 URL 类 Socket 通信机制 多线程服务器 数据报文通信 广播式通信
多线程服务器 • 服务器程序一般都向客户程序网络提供资源。客 户程序向服务器程序发送请求, 而服务器程序则 对该请求作出应答。 • 处理一个以上客户请求的方法之一是使服务器程 序多线程化。多线程的服务器 为每一个从客户机 接收到的通信创建一个线程。线程是一个独立于 运行程序和其 他线程的指令序列。 • 通过使用线程,多线程化的服务器程序就可以接 受来自客户机的连接,启动该 通信的线程并继续 监视来自其它客户机的请求。
多线程服务器原理 • 上述代码只能在服务器程序和一个客户程 序之间工作 • 若要实现多客户连接,就必须把服务器程 序转化为一个多线程化的服务器程序 • 多线程化服务器程序为每个客户请求生成 一个新线程,这样,每个客户机就有了自 己与服务器来往传递数据的连接。当运行 多个线程时,用户必须确保一个线程不会 受到其它线程中数据的干扰
创建服务器端 public void listenSocket(){ try{ server = new ServerSocket(4444); } catch (IOException e){ System.out.println("Could not listen on port 4444"); System.exit(-1); } while(true){ ClientWorker w; try{ //server.accept returns a client connection w = new ClientWorker(server.accept(), textArea); Thread t = new Thread(w); t.start(); } catch (IOException e) { System.out.println("Accept failed: 4444"); System.exit(-1); }}}
线程 class ClientWorker implements Runnable { private Socket client; private JTextArea textArea; //Constructor ClientWorker(Socket client, JTextArea textArea){ this.client = client; this.textArea = textArea; } public void run(){ String line; BufferedReader in = null; PrintWriter out = null; try{ in = new BufferedReader(new InputStreamReader(client.getInputStream())); out = new PrintWriter(client.getOutputStream(), true); } catch (IOException e) { System.out.println("in or out failed"); System.exit(-1); } while(true){ try{ line = in.readLine(); //Send data back to client out.println(line); //Append data to text area textArea.append(line); }catch (IOException e) { System.out.println("Read failed"); System.exit(-1);
网络部分 网络基础理论 InetAddress 类 URL 类 Socket 通信机制 多线程服务器 数据报文通信 广播式通信
数据报通信 • 数据报是网上传输的独立数据包 ,数据报 是否能正确地到达目的地,到达的时间, 顺序,内容的正确性均没有保障 • java.net 包中有两个类 DatagramSocket 和 DatagramPacket ,为应用程序中采用数据报 通信方式进行网络通信
DategramPacket 包 • DategramPacket 类用来创建数据包 – 数据包有两种,一种用来传递数据包,该数据包有要 传递到的目的地址;另一种数据包用来接收传递过来 的数据包中的数据 – 要创建接收的数据包,通过 DatagramPackett 类的方法构 造: public DatagramPacket(byte ibuft[],int ilength) public DatagramPacket( byte ibuft[],int offset ,int ilength) – 创建发送数据包的构造方法为: public DatagramPacket ( byt ibuf[],int ilength,InetAddrss iaddr,int port ) public DatagramPacket ( byt ibuf[],int offset , int ilength,InetAddrss iaddr,int port )
一些基本方法 • • • •
• •
public InetAddress getAddress() 如果是发送数据包,则获得数据包要发送 的目标地址,但是如果是接收数据包则返回发送此数据包的源地址 public byte [] getData() 返回一个字节数组,其中是数据包的数据。如 果想把字节数组转换成别的类型就要进行转化 public int getLength() 获得数据包中数据的字节数。 pubic int getPort( ) 返回数据包中的目标地址的主机端口号。发送和接收 数据包还需要发送和接收数据包的套接字,即 DatagramSocket 对象, DatagramSocket 套接字在本地机器端口监听是否有数据到达或者将数 据包发送出去 public DatagramSocket() 用本地机上任何一个可用的端口创建一个套接 字,这个端口号是由系统随机产生的 public DatagramSocket ( int port )用一个指定的端口号 port 创建一个套 接字
Datagram 通信方式 • Java 的 java.net.package 通过 DatagramPacket 和 DatagramSocket 类来收发 datagram • 这两个类的创建和用法并不相同 – 要发送数据报,首先要创建一个 DatagramPacket ,指定 要发送的数据和数据长度,发送的主机地址和端口号 ,然后用 DatagramSocket 类的 Send() 方法发送数据 – 要接收数据报,首先要创建 DatagramSocket 对象来监听 主机上的端口,然后创建 Datagram Packet 对象,指定缓 冲区接收数据。最后, DatagramSocket 的 receive() 方法 接收数据
数据报通信原理
例——多线程数据报服务器 import java.io.*; public class QuoteServer { public static void main(String[] args) throws IOException { new QuoteServerThread().start(); } }
import java.io.*; import java.net.*; import java.util.*; public class QuoteServerThread extends Thread { protected DatagramSocket socket = null; protected BufferedReader in = null; protected boolean moreQuotes = true; public QuoteServerThread() throws IOException { this("QuoteServerThread"); } public QuoteServerThread(String name) throws IOException { super(name); socket = new DatagramSocket(4445); try { in = new BufferedReader(new FileReader("one-liners.txt")); } catch (FileNotFoundException e) { System.err.println("Could not open quote file. Serving time instead."); } } public void run() { while (moreQuotes) { try { byte[] buf = new byte[256]; // receive request DatagramPacket packet = new DatagramPacket(buf, buf.length); socket.receive(packet); // figure out response String dString = null; if (in == null) dString = new Date().toString(); else dString = getNextQuote();
buf = dString.getBytes(); // send the response to the client at "address" and "port" InetAddress address = packet.getAddress(); int port = packet.getPort(); packet = new DatagramPacket(buf, buf.length, address, port); socket.send(packet); } catch (IOException e) { e.printStackTrace(); moreQuotes = false; } } socket.close(); } protected String getNextQuote() { String returnValue = null; try { if ((returnValue = in.readLine()) == null) { in.close(); moreQuotes = false; returnValue = "No more quotes. Goodbye."; } } catch (IOException e) { returnValue = "IOException occurred in server."; } return returnValue; } }
import java.io.*; import java.net.*; import java.util.*; public class QuoteClient { public static void main(String[] args) throws IOException { if (args.length != 1) { System.out.println("Usage: java QuoteClient "); return; } // get a datagram socket DatagramSocket socket = new DatagramSocket(); // send request byte[] buf = new byte[256]; InetAddress address = InetAddress.getByName(args[0]); DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 4445); socket.send(packet); // get response packet = new DatagramPacket(buf, buf.length); socket.receive(packet); // display response String received = new String(packet.getData(), 0); System.out.println("Quote of the Moment: " + received); socket.close(); } }
例——端口扫描 import java.net.*; public class UDPScan { public static void main(String args[]){ for (int port=1024;port<=65535;port++) { try { DatagramSocket server=new DatagramSocket(port); server.close(); }catch(SocketException e){ System.out.println("there is a server in port "+port+"."); } } } }
网络部分 网络基础理论 InetAddress 类 URL 类 Socket 通信机制 多线程服务器 数据报文通信 广播式通信
广播式通信 • 服务器一端以一定的间歇广播发送数据,客户端 被动接收 • java 的 MulticastSocket 类可以实现广播发送 • datagramsocket 只允许数据报发送一个目的地址, java.net 包中提供了一个类 multicastsocket ,允许数 据以广播方式发送到该端口的所有用户 • multicastsocket 用在客户端,监听服务器广播来的 数据
例——多线程广播服务器 public class MulticastServer { public static void main(String[] args)throws java.io.IOException { new MulticastServerThread().start(); } }
import java.io.*; import java.net.*; import java.util.*; public class MulticastServerThread extends QuoteServerThread { private long FIVE_SECONDS = 5000; public MulticastServerThread() throws IOException{ super("MulticastServerThread"); } public void run() { while (moreQuotes) { try { byte[] buf = new byte[256]; // construct quote String dString = null; if (in == null) dString = new Date().toString(); else dString = getNextQuote(); buf = dString.getBytes(); // send it InetAddress group = InetAddress.getByName("230.0.0.1"); DatagramPacket packet = new DatagramPacket(buf, buf.length, group, 4446); socket.send(packet); // sleep for a while try{ sleep((long)(Math.random() * FIVE_SECONDS)); } catch (InterruptedException e) { } } catch (IOException e) { e.printStackTrace(); moreQuotes = false; } } socket.close(); }}
import java.io.*; import java.net.*; import java.util.*; public class MulticastClient { public static void main(String[] args) throws IOException { MulticastSocket socket = new MulticastSocket(4446); InetAddress address = InetAddress.getByName("230.0.0.1"); socket.joinGroup(address); DatagramPacket packet; // get a few quotes for (int i = 0; i < 5; i++) { byte[] buf = new byte[256]; packet = new DatagramPacket(buf, buf.length); socket.receive(packet); String received = new String(packet.getData()); System.out.println("Quote of the Moment: " + received); } socket.leaveGroup(address); socket.close(); } }
练习 1. 分析并运行前述 client/server 程序,体会 Socket 编程原理及其实现机制; 2. 在 1 的基础上,编写程序实现一对一的聊天 程序 (talkshow) : client 和 server 端程序建立 连接后双方可以自由通话;
小结 • 掌握 : – 网络基础与协议原理 – URL 类的用法 – 建立 Socket 通信的步骤
• 了解: – 多线程服务器原理 – 数据报通信方式 – 广播