黑马程序员---回顾之java网络编程

------- android培训、java培训、期待与您交流! ----------

1.网络模型

OSI的网络模型分为七层:应用层,表示层,会话层,传输层,网络层,数据链路层,物理层,数据在传输的同时是进行一层一层封包和拆包的。
TCP/IP的网络模型:应用层,传输层,网际层,网络接口层。


七层简述:

1.层物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后在转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。

2.层数据链路层:主要将从物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装。常把这一层的数据叫做帧。在这一层工作的设备是交换机,数据通过交换机来传输。

3.层网络层:主要将从下层接收到的数据进行IP地址(例192.168.0.1)的封装与解封装。在这一层工作的设备是路由器,常把这一层的数据叫做数据包。

4.层传输层:定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。

5.会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)

6.表示层:主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够能识别的东西(如图片、声音等)。

7.应用层: 主要是一些终端的应用,比如说FTP(各种文件下载),WEB(IE浏览),QQ之类的(可以把它理解成我们在电脑屏幕上可以看到的东西.就是终端应用)。

2.网络通讯要素

1 ip地址(InetAddress):

两台计算机,进行通信需要借助于网络设备的同时,计算机内部是怎么处理的呢?感觉我自己的认识概述如下。一台计算机想要通信首先要找到目标机,只要找到对象才有可能实现通信,这就引出了IP的概念,通信的计算机之间是通过IP地址来查找相应的目标计算机的。

2.端口号:

两台计算机通过网线连接一起后,在遵守TCP/IP协议的前提下,通过IP地址进行通信。每台计算机又有很多的应用程序,如果一台计算机发送数据到另一个计算机上,具体是哪一个应用程序接收呢?这个就需要有端口来区别。计算机一共分配了0--65535个数据用来表示端口,其中0~1024系统使用或保留端口。

3传输协议:

尽管TCP/IP协议的名称中只有TCP这个协议名,但是在TCP/IP的传输层同时存在TCP和UDP两个协议。

UDP协议特点:

将数据及源和目的封装成数据包中,不需要建立连接
每个数据报的大小在限制在64k内
因无连接,是不可靠协议
不需要建立连接,速度快

TCP协议特点:

建立连接,形成传输数据的通道。
在连接中进行大数据量传输
通过三次握手完成连接,是可靠协议
必须建立连接,效率会稍低

3.Socket编程

Socket就是为网络服务提供的一种机制,通信的两端都有Socket,网络通信其实就是Socket间的通信。

3.1基于UDP协议的Socket编程

java中用来网络编程的包是:java.net;
UDP协议通信使用的是java包中的DatagramSocket和DatagramPacket对象。建立通信机制的步骤是:
1.通过DatagramSocket对象是为网络通信构建一个通道,专业的叫法就是创建端口。
发送端具体实现代码:DatagramSocket ds = new DatagramSocket();
如果是发送端的话,这个端口可以不进行绑定,使用内核自由分配的端口号即可。如果是接受端的话,这个端口
要必须要绑定到特定的端口,这个端口也可以叫做监视器。监视某个端口信息的变化。接收端具体实现代码:
DatagramSocket ds = new DatagramSocket(端口号)。

2.封包操作。

如果是发送端的话,首先要有数据,由于网络传输的都是二进制数据,所以在定义网络包的时候也要定义成二进制形式的。具体定义代码如下:
发送数据包数据:byte[] buf1 = "数据".getBytes();
接受数据包数据:byte[] buf2 = new byte[1024];
有了数据和数据缓冲区后,可以把这个数据和数据缓冲区封装成网络包:
发送端的数据包:DatagramPacket dp =
new DatagramPacket(buf1,buf1.length,InetAddress.getAddress("192.168.1.104"),10000);
接受端的数据包:DatagramPacket dp = new DatagramPacket(buf2,buf2.length);

3.发送接受操作。
根据端口Socket的方法,对数据包发送和接受操作。具体实现代码:
发送端:ds.send(dp);
接收端:ds.receive(dp); 接收到的数据包放到接收端定义的数据包缓冲区中。

4.关闭资源。
ds.close();

5.UDP经典案例之聊天程序

package cn.djb.chart;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public class ChartRoom {

	/**
	 * @param args
	 * @throws SocketException 
	 */
	public static void main(String[] args) throws SocketException {
		//创建一个发送端
		DatagramSocket ds1=new DatagramSocket();
		//创建一个接收端
		DatagramSocket ds2=new DatagramSocket(10000);
		//创建一个接收端线程并启动
		new Thread(new Send(ds1)).start();
		//创建一个接收端线程并启动
		new Thread(new Receive(ds2)).start();
		

	}
}

class Send implements Runnable{
	private DatagramSocket ds;
	public Send(DatagramSocket ds){
		this.ds=ds;
	}
	public void run() {
		BufferedReader br=null;
		try{
		//创建一个键盘录入流
		br=new BufferedReader(new InputStreamReader(System.in));
		//读取键盘录入数据并发送
		String line=null;
		while((line=br.readLine())!=null){
			//用读取数据创建发送数据包
			byte[] buf=line.getBytes();
			DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),10000);
			//发送端发送数据
			ds.send(dp);
		}
		}catch (Exception e) {
			throw new RuntimeException("发送端失败")
		}finally{//释放资源
			if(br!=null)
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
		
	}
	
}
class Receive implements Runnable{
	private DatagramSocket ds;
	public Receive(DatagramSocket ds){
		this.ds=ds;
	}
	public void run() {
		try{
		while(true){
			//定义一个缓冲数组
			byte[] buf=new byte[1024];
			//用缓冲数组创建一个接收数据包
			DatagramPacket dp=new DatagramPacket(buf,buf.length);
			//接受数据,并显示
			ds.receive(dp);//receive是一个阻塞式方法
			String ip=dp.getAddress().getHostAddress();
			String content=new String(dp.getData(),0,dp.getLength());
			System.out.println(ip+":"+content);
		}
		}catch (Exception e) {
			throw new RuntimeException("接收端失败");
		}
		}
	
}

3.2基于TCP协议的Socket编程

1.TCP协议通信使用的是java.net包中的Socket和ServerSocket对象。TCP和UDP的区别在于,TCP是建立连接,UDP是不需要连接,TCP操作的是端口输入输出流对象,UDP操作的是DatagramPacket包。按照TCP通信时不需要建立包,直接获取输入输出流操作即可。通信机制的
步骤如下:

2.TCP通信首先也是要建立Socket端口。UDP中客户端和服务端都是使用的DatagramSocket创建对象的方法,创建通信端口。TCP建立端口时,客户端和服务端是使用不一样的类。具体操作代码如下:
客户端:Socket s = new Socket();
服务端:ServerSocket ss = new ServerSocket(监听端口);

3.建立连接操作
通过服务端ServerSocket对象的accept方法获得端口连接,在获得请求端口信息后,建立连接。

4.获得输入输出流操作。
在客户端获得Socket的getOutputStream()方法,通过该方法,输出数据。在服务端通过获得Socket的
getInputStream()方法,读取数据。

5.关闭资源操作。
客户端:s.close();
服务端:s.close; ss.close();

案例:客户端发送字符串给服务端,服务端反转并返回给客户端

package com.itheima;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 10、 使用TCP协议完成一个客户端一个服务器。客户端从键盘输入读取一个字符串,发送到服务器。
 * 服务器接收客户端发送的字符串,反转之后发回客户端。客户端接收并打印
 * 
 * @author Administrator
 * 
 */
public class Test10 {

	public static void main(String[] args) {
		// 创建并运行一个服务端线程
		new Thread(new TcpServer()).start();
		// 创建并运行一个客户端线程
		new Thread(new TcpClient()).start();
	}
}

class TcpClient implements Runnable {
	
	public void run() {
		BufferedWriter bw = null;
		BufferedReader br = null;
		BufferedReader br2 = null;
		Socket s = null;
		try {
			// 建立一个socket客户端端
			s = new Socket("127.0.0.1", 11000);
			// 拿到与键盘相关的输入流
			br = new BufferedReader(new InputStreamReader(System.in));
			// 拿到服务端回送数据的输入流
			br2 = new BufferedReader(new InputStreamReader(s.getInputStream()));
			// 拿到客户端的输出流
			bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
			// 循环向服务端发送数据并接受服务端回写的数据打印
			String line = null;
			while ((line = br.readLine()) != null) {
				if ("over".equals(line.trim()))
					break;
				bw.write(line);
				bw.newLine();
				bw.flush();
				String str = br2.readLine();
				System.out.println(str);
			}
		} catch (UnknownHostException e) {
			throw new RuntimeException("未知主机名");
		} catch (IOException e) {
			throw new RuntimeException("客户端建立失败");
		} finally {//释放资源
			if (s != null)
				try {
					s.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			if (br != null)
				try {
					br.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			if (br2 != null)
				try {
					br2.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			if (bw != null)
				try {
					bw.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
	}
}

class TcpServer implements Runnable {

	public void run() {
		BufferedWriter bw = null;
		BufferedReader br = null;
		Socket s = null;
		ServerSocket ss = null;
		try {
			// 建立一个socket服务端,并绑定一个端口号
			ss = new ServerSocket(11000);
			// 获取客户端socket对象
			s = ss.accept();
			// 获取客户端ip
			String ip = s.getInetAddress().getHostAddress();
			System.out.println("ip:" + ip + "...connect");
			// 获取客户端的输入流
			br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			// 获取给客户端回送数据的输出流
			bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
			// 循环反转字符串并回送给客户端
			String line = null;
			while ((line = br.readLine()) != null) {
				char[] chars = line.toCharArray();
				reversal(chars);
				String str = new String(chars);
				bw.write("server:" + str);
				bw.newLine();
				bw.flush();
			}
		} catch (IOException e) {
			throw new RuntimeException();
		} finally {//释放资源
			if (s != null)
				try {
					s.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			if (ss != null)
				try {
					ss.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			if (br != null)
				try {
					br.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			if (bw != null)
				try {
					bw.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

		}

	}

	private void reversal(char[] chars) {
		int start = 0;
		int end = chars.length - 1;
		while (true) {
			if (start >= end)
				break;
			char temp = chars[start];
			chars[start] = chars[end];
			chars[end] = temp;
			start++;
			end--;
		}
	}
}

4..基于URL高层次的网络编程

4.1统一资源定位符URL

URL(Uniform Resource Locator)是统一资源定位符的简称,它表示Internet上某一资源的地址。通过URL我们可以访问Internet上的各种网络资源,比如最常见的WWW,FTP站点。浏览器通过解析给定的URL可以在网络上查找相应的文件或其他资源。

4.2 URL的组成

protocol://resourceName
协议名(protocol)指明获取资源所使用的传输协议,如http、ftp、gopher、file等,资源(resourceName)则应该是资源的完整地址,包括主机名、端口号、文件名或文件内部的一个引用。例如:
http://www.sun.com/ 协议名://主机名
http://home.netscape.com/home/welcome.html 协议名://机器名+文件名
http://www.gamelan.com:80/Gamelan/network.html#BOTTOM 协议名://机器名+端口号+文件名+内部引用

4.3 创建一个URL

为了表示URL, java.net中实现了类URL。我们可以通过下面的构造方法来初始化一个URL对象:
  (1) public URL (String spec);
     通过一个表示URL地址的字符串可以构造一个URL对象。
     URL urlBase=new URL("http://www. 263.net/") 
  (2) public URL(URL context, String spec);
     通过基URL和相对URL构造一个URL对象。
     URL net263=new URL ("http://www.263.net/");
     URL index263=new URL(net263, "index.html")
  (3) public URL(String protocol, String host, String file);
     new URL("http", "www.gamelan.com", "/pages/Gamelan.net. html");
  (4) public URL(String protocol, String host, int port, String file);
     URL gamelan=new URL("http", "www.gamelan.com",80,"Pages/Gamelan.network.html");
注意:类URL的构造方法都抛出编译时异常(MalformedURLException),因此生成URL对象时,我们必须要对这一例外进行处理,通常是用try-catch语句进行捕获。格式如下:
try{
      URL myURL= new URL(…)
}catch (MalformedURLException e){
      …  
}

4.4 解析一个URL

一个URL对象生成后,其属性是不能被改变的,但是我们可以通过类URL所提供的方法来获取这些属性:
   public String getProtocol() 获取该URL的协议名。
   public String 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() 获得使用者的信息
   public String getRef() 获得该URL的锚

4.5 从URL读取网络资源

当我们得到一个URL对象后,就可以通过它读取指定的资源。这时我们将使用URL的方法openStream(),方法openSteam()与指定的URL建立连接并返回InputStream类的对象以从这一连接中读取数据。

package cn.djb.url;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;

public class URLTest {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		URL url = new URL("http://www.baidu.com");
		BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
		String line = null;
		while((line=br.readLine())!=null){
			System.out.println(line);
		}
	}

}

4.6 通过URLConnetction连接

通过URL的方法openStream(),我们只能从网络上读取数据,如果我们同时还想输出数据,例如向服务器端的CGI程序发送一些数据,我们必须先与URL建立连接,然后才能对其进行读写,这时就要用到类URLConnection了。CGI是公共网关接口(Common Gateway Interface)的简称,它是用户浏览器和服务器端的应用程序进行连接的接口。
类URLConnection也在包java.net中定义,它表示Java程序和URL在网络上的通信连接。当与一个URL建立连接时,首先要在一个URL对象上通过方法openConnection()生成对应的URLConnection对象。例如下面的程序段首先生成一个指向地址http://www.baidu.com的对象,然后用openConnection()打开该URL对象上的一个连接,返回一个URLConnection对象。如果连接过程失败,将产生IOException

类URLConnection提供了很多方法来设置或获取连接参数,程序设计时最常使用的是getInputStream()和getOurputStream(),通过返回的输入/输出流我们可以与远程对象进行通信。看下面的例子:

package cn.djb.url;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;

public class URLConnectionTest {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		 //创建URL对象
		URL url = new URL("http://www.baidu.com");
		 //由URL对象获取URLConnection对象
		URLConnection conn = url.openConnection();
		conn.setDoOutput(true);
		//由URLConnection获取输出流转换成字符流构造BufferedWriter
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
		//向服务器写出数据
		bw.write("你好百度服务器");
		bw.close();
		//由URLConnection获取输入流,转换成字符流构造BufferedReader
		BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
		//读取数据
		String line = br.readLine();
		System.out.println(line);
		br.close();
	
	}

}

实际上,类URL的方法openSteam()是通过URLConnection来实现的。它等价于openConnection().getInputStream();基于URL的网络编程在底层其实还是基于上面讲的Socket接口的。WWW,FTP等标准化的网络服务都是基于TCP协议的,所以本质上讲URL编程也是基于TCP的一种应用.

------- android培训、java培训、期待与您交流! ----------

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值