该课内容: Java网络编程. 基于TCP的套接字编程. 基于UDP的套接字编程. URL和URI.一个实用的下载程序.
—计算机网络.
计算机网络是相互连接的独立自主的计算机的集合. 最简单的网络形式由两台计算机组成.
—IP地址.
- IP网络中每台主机都必须有一个惟一的IP地址.
- IP地址是一个逻辑地址.
- 因特网上的IP地址具有全球唯一性.
- 32位. 4个字节. 常用点分十进制的格式表示. 例如. 192.168.0.16
—协议.
- 为进行网络中的数据交换(通信)而建立的规则、标准或约定。(=语义+语法+规则)
- 不同层具有各自不同的协议
—ISO/OSI七层参考模型.
- 通信实体的对等层之间不允许直接通信.
- 各层之间是严格单向依赖.
- 上层使用下层提供的服务— Service user.
- 下层向上层提供服务 — Service provider.
—OSI各层所使用的协议.
- 应用层:远程登录协议Telnet. 文件传输协议FTP. 超文本传输协议HTTP. 域名服务DNS. 简单邮件传输协议SMTP. 邮局协议POP3等.
- 传输层:传输控制协议TCP、用户数据报协议UDP。
a) TCP:面向连接的可靠的传输协议。
b) UDP:是无连接的,不可靠的传输协议。
- 网络层:网际协议IP、Internet互联网控制报文协议ICMP、Internet组管理协议IGMP。
—数据封装.
- OSI参考模型中. 对等层协议之间交换的信息单元统称为协议数据单元(PDU,Protocol Data Unit).
- OSI参考模型中每一层都要依靠下一层提供的服务.
- 为了提供服务. 下层把上层的PDU作为本层的数据封装. 然后加入本层的头部(和尾部). 头部中含有完成数据传输所需的控制信息.
- 这样. 数据自上而下递交的过程实际上就是不断封装的过程. 到达目的地后自下而上递交的过程就是不断拆封的过程. 由此可知. 在物理线路上传输的数据. 其外面实际上被包封了多层“信封”.
- 但是. 某一层只能识别由对等层封装的“信封”. 而对于被封装在“信封”内部的数据仅仅是拆封后将其提交给上层. 本层不作任何处理.
—TCP/IP模型.
TCP/IP包括: 应用层. 传输层. 网络层. 网络接口.
—端口.
- 端口是一种抽象的软件结构(包括一些数据结构和I/O缓冲区). 应用程序通过系统调用与某端口建立连接(binding)后. 传输层传给该端口的数据都被相应的进程所接收. 相应进程发给传输层的数据都通过该端口输出.
- 端口用一个整数型标识符来表示. 即端口号. 端口号跟协议相关. TCP/IP传输层的两个协议TCP和UDP是完全独立的两个软件模块. 因此各自的端口号也相互独立. 端口通常称为协议端口(protocol port) . 简称端口.
- 端口使用一个16位的数字来表示. 它的范围是0~65535. 1024以下的端口号保留给预定义的服务. 例如. http使用80端口.
—基于TCP的socket编程.
- 服务器程序编写:
①调用ServerSocket(int port)创建一个服务器端套接字,并绑定到指定端口上;②调用accept(),监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字。③调用Socket类的getOutputStream()和getInputStream获取输出流和输入流,开始网络数据的发送和接收。④最后关闭通信套接字。
- 客户端程序编写:
①调用Socket()创建一个流套接字,并连接到服务器端; ②调用Socket类的getOutputStream()和getInputStream获取输出流和输入流,开始网络数据的发送和接收。 ③最后关闭通信套接字。
EX. 基于TCP的Socket编程
package test; import java.net.*; import java.io.*; public class Test extends Thread{ private Socket s; public Test (Socket s){ this.s = s; } public void run(){ try{ OutputStream os = s.getOutputStream(); InputStream is = s.getInputStream(); os.write("hello.".getBytes()); byte[] buf = new byte[100]; int len = is.read(buf); System.out.println(new String(buf, 0, len)); os.close(); is.close(); s.close(); } catch (Exception ex){ ex.printStackTrace(); } } public static void main(String[] args){ if (args.length > 0) server(); else client(); } public static void server(){ try{ // 创建套接字.绑定到端口号为6000的端口上. ServerSocket ss = new ServerSocket(6000); // 一旦有请求就创建一个线程.进行处理 while (true){ Socket s = ss.accept(); new Test(s).start(); } //ss.close(); } catch(Exception ex){ ex.printStackTrace(); } } public static void client(){ try{ // 客户端的端口需要与服务器端口号相同. // 注意这里ip地址使用的是本机地址. Socket s = new Socket(InetAddress.getByName(null), 6000); OutputStream os = s.getOutputStream(); InputStream is = s.getInputStream(); os.write("hello too.".getBytes()); byte[] buf = new byte[100]; int len = is.read(buf); System.out.println(new String(buf, 0, len)); os.close(); is.close(); s.close(); } catch(Exception ex){ ex.printStackTrace(); } } }
—基于UDP的socket编程.
- 接收端程序编写:
①调用DatagramSocket(int port)创建一个数据报套接字,并绑定到指定端口上;②调用DatagramPacket(byte[] buf, int length),建立一个字节数组以接收UDP包 。③调用DatagramSocket类的receive(),接收UDP包。④最后关闭数据报套接字。
- 发送端程序编写:
①用DatagramSocket()创建一个数据报套接字; ②调用DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port),建立要发送的UDP包。 ③调用DatagramSocket类的send(),发送UDP包。④最后关闭数据报套接字。
EX. 基于UDP的Socket编程
package test; import java.net.*; import java.io.*; public class Test extends Thread{ public static void main(String[] args){ } public static void recv(){ try{ DatagramSocket ds = new DatagramSocket(6000); byte[] buf = new byte[100]; DatagramPacket dp = new DatagramPacket(buf, 100); ds.receive(dp); System.out.println(new String(buf, 0, dp.getLength())); String str = "hello too"; DatagramPacket dpSend = new DatagramPacket(str.getBytes(), str.length(), dp.getAddress(), dp.getPort()); ds.send(dpSend); ds.close(); } catch (Exception ex){ ex.printStackTrace(); } } public static void send(){ try{ DatagramSocket ds = new DatagramSocket(); String str = "Hello"; DatagramPacket dp = new DatagramPacket(str.getBytes(), str.length(), InetAddress.getByName(null), 6000); ds.send(dp); byte[] buf = new byte[100]; DatagramPacket dpRecv = new DatagramPacket(buf, 100); ds.receive(dpRecv); System.out.println(new String(buf, 0, dpRecv.getLength())); ds.close(); } catch (Exception ex){ ex.printStackTrace(); } } }
—URL与URI.
- URL(Uniform Resource Locator ),通用资源定位符。http://www.mybole.com.cn/index.asp就是一个URL。
- URI(Uniform Resource Identifier),通用资源标识符。
- URI纯粹是个符号结构,用于指定构成Web资源的字符串的各个不同部分。URL是一种特殊类型的URI,它包含了用于查找某个资源的足够信息。其它的URI,例如:mailto:myoble@mybole.com.cn则不属于定位符,因为它里面不存在根据该标识符来查找的任何数据。这种URI称为URN(通用资源名)。
- 在Java库中,URI类不包含用于访问通用资源标识符设定的任何方法,它的唯一作用是进行分析。相反,URL类则可以打开到达资源的一个字符串。
EX. 文件下载例子.
package test; import java.net.*; import javax.swing.*; import java.awt.event.*; import java.io.*; public class Test extends Thread{ public static void main(String[] args){ JFrame jf = new JFrame("download"); jf.setSize(600, 400); jf.setLocation(100, 100); JPanel p = new JPanel(); JLabel l = new JLabel("input URL:"); final JTextField tf = new JTextField(30); p.add(l); p.add(tf); jf.getContentPane().add(p, "North"); final JTextArea ta = new JTextArea(); jf.getContentPane().add(ta, "Center"); JButton btn = new JButton("download"); btn.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ String str = tf.getText(); try{ URL url1 = new URL(str); URLConnection urlconn = url1.openConnection(); String line = System.getProperty("line.separator"); ta.append("Host " + url1.getHost() + line); ta.append("Port " + url1.getDefaultPort() + line); ta.append("ContentType " + urlconn.getContentType() + line); ta.append("ContextLength " + urlconn.getContentLength()); InputStream is = urlconn.getInputStream(); FileOutputStream fos = new FileOutputStream("1.html"); int data; while ((data = is.read()) != -1){ fos.write(data); } fos.close(); is.close(); } catch (Exception ex){ ex.printStackTrace(); } } }); jf.getContentPane().add(btn, "South"); jf.addWindowListener(new WindowAdapter(){ public void WindowClosing(WindowEvent e){ System.exit(0); } }); jf.show(); } }