day23、24
1.网络通讯的要素:
- 找到对方IP
- 数据要发送到对方指定的应用程序上,为了标识这些应用程序,所以给这些网络应用程序都用数字进行标识。为了方便称呼,该数字叫做 端口! (这是逻辑接口)
- 定义通讯规则,这个规则就是: 协议! 国际通用协议TCP/IP 还有很多其他协议
特殊IP: 127.0.0.1是回送地址,指默认情况下的本机地址
常见端口: web服务器80 Tomcat服务器8080 MySQL3306
2.传输协议有2种: TCP UDP
OSI模型: 应用层 表示层 对话层 传输层 网络层 数据链路层 物理层
TCP/IP模型: 应用层 传输层 网际层 主机-网络层
javaweb开发处于: 应用层。
应用层的协议包括: HTTP FTP 等
其中传输层定义了TCP、UDP协议, 网际层定义了IP协议, java网络编程处理的是:网络层、传输层,不经过应用层
3.
- IP地址:网络中设备的标识。 本机回环IP127.0.0.1 主机名:localhost
- 端口号:用于标识进程的逻辑地址。 有效端口 0-65535, 0-1024为系统使用,即保留端口
- 传输协议:通讯的规则。 常见协议 TCP UDP
4.InetAddress 类
该类没有构造函数,通过各种get方法获取对象。 由主机名+地址组成,如: www.baidu.com/111.13.100.92
InetAddress ip = InetAddress.getLocalHost(); System.out.println(ip); System.out.println(ip.getHostAddress()); System.out.println(ip.getHostName()); static InetAddress getLocalHost() //返回本地主机。 String getHostAddress()// 返回对象的原始IP地址 String getHostName() // 返回对象的主机名 static InetAddress getByName(String host) //返回指定主机的一个IP对象 static InetAddress[] getAllByName(String host) //返回指定主机的所有IP对象 static InetAddress getByAddress(byte[] addr) InetAddress ip = InetAddress.getLocalHost(); System.out.println(ip); //输出tyh-PC/192.168.252.1 System.out.println(ip.getHostAddress()); //输出192.168.252.1 System.out.println(ip.getHostName()); //输出tyh-PC
//给定主机名,会去联机查找其ip地址,返回主机名/地址 //找不到时,抛出UnknownHostException异常 InetAddress ip=InetAddress.getByName("www.qq.com"); System.out.println(ip);//www.qq.com/111.30.132.101 //给定ip地址得到ip对象,这种方式不会去查找name,仅仅创建一个ip对象 //尽管这是百度ip,因为不联网查找,不知道主机名 byte[] by = {111,13,100,92}; InetAddress ip = InetAddress.getByAddress(by); System.out.println(ip.getHostName());//111.12.100.92
//一台主机可以有多个IP地址 InetAddress[] is = InetAddress.getAllByName("www.baidu.com"); for(InetAddress i:is) System.out.println(i);//www.baidu.com/111.13.100.91 //www.baidu.com/111.13.100.92
5.TCP和UDP:
UDP协议特点: User Datagram Protocol的简称, 中文名是用户数据报协议
- 将数据及源和目的封装成数据包中,不需要建立连接
- 每个数据报的大小限制在 64K
- 因无连接,是不可靠协议
- 不需要建立连接,速度快
- 常用于: 视频传输 音频传输
TCP协议特点:
- 建立连接,形成建立数据的通道
- 在连接中进行大数据量传输
- 通过三次握手完成连接,是可靠协议
- 必须建立连接,效率会稍低
6. Socket java网络编程指的就是Socket编程,Socket是为网络服务提供的一种机制
- 通信的两端都有Socket,网络通信其实就是Socket的通信
- 数据在两个Socket间通过IO传输
7. UDP传输
定义UDP发送端:
- 建立Socket服务。
- 提供数据,并将数据封装到数据包中。
- 通过Socket服务中的发送功能,将数据包发出去。
- 关闭资源。
定义UDP接收端:
- 定义Socket服务,需要监听一个端口。其实就是给这个接收网络应用程序定义数字标识。
- 定义数据包,用于存储接收的字节数据。 数据包对象的方法可以提取指定的数据
- 通过Socket服务的receive方法将接收到的数据存入已经定义好的数据包中。
- 通过数据包对象的特有功能,将这些数据取出
- p关闭资源。
class UdpSend { public static void main(String[] args)throws Exception { //1.创建socket服务,通过DatagramSocket对象 //可以不指定端口号,系统会随机分配一个 //一台机器的一个端口在同一时间只能被一个程序占用,否则抛出Bind绑定异常 DatagramSocket ds = new DatagramSocket(9000); //2.确定数据,封装成数据包 byte[] buf = "udp 发送开始了。。。。".getBytes(); byte[] byip = {112,37,77,68};//本机临时ip byte[] byip2 = {127,0,0,1}; //本机回环ip DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByAddress(byip2), 10000); //当ip的后面是255时,代表广播地址,可以把数据广播到局域网 //3.通过socket服务,将已有的数据包发送出去 ds.send(dp); //4.关闭资源 ds.close(); } }
- class UdpRec { public static void main(String[] args)throws Exception { //1.创建socket,这里要指定需要监听的端口 DatagramSocket ds = new DatagramSocket(9999); //定义数据包,用于存储数据 byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf, buf.length); //通过服务的receive方法将收到的数据存入数据包中。 //receive是一个阻塞式方法,没收到数据,就会一直wait ds.receive(dp); //通过数据包的方法取出包中的数据 String ip = dp.getAddress().getHostAddress(); String data = new String(dp.getData(),0,dp.getLength()); int port = dp.getPort(); System.out.println(ip+"::"+data+"::"+port); //关闭资源 ds.close(); } }
8.TCP传输:
不同于UDP,分为客户端、服务端, Socket、 ServerSocket
客户端:
- 创建Socket服务,指定要连接的主机和端口
- 使用Socket的输出流发送数据
- 关闭Socket对象
服务端:
- 建立服务端的Socket服务,ServerSocket,并监听一个端口
- 获取连接过来的客户端对象,通过accept方法
- 使用客户端对象的流读取和发送数据
- 关闭Socket对象,关闭服务端对象
class TcpClient { public static void main(String[] args) throws Exception{ //创建客户端的Socket服务,指定目的主机和端口 Socket s = new Socket("127.0.0.1",9999); //为了发送数据,应该获取Socket流中的输出流 OutputStream out = s.getOutputStream(); out.write("网络编程".getBytes()); s.close(); } }
class TcpServer { public static void main(String[] args)throws Exception { // 建立服务端Socket服务,并监听一个端口 ServerSocket ss = new ServerSocket(9999); //通过accept方法来获取连接过来的客户端对象 Socket s = ss.accept(); System.out.println("连接成功"); //获取客户端对象发送过来的数据, InputStream in = s.getInputStream(); byte[] buf = new byte[1024]; int len = in.read(buf); System.out.println(new String(buf,0,len)); s.close(); ss.close(); } }
ServerSocket类有一种特殊构造方法:
ServerSocket(int port, int backlog)
backlog - 队列的最大长度, 即能连接到服务器的最多客户端个数。
9.为了让多个客户端同时并发访问服务端,服务端最好的做法是将每个客户端封装到一个单独的线程中,这样,就可以同时处理多个客户端请求。
class PicClient { public static void main(String[] args)throws Exception { // TODO Auto-generated method stub Socket s = new Socket("127.0.0.1", 10000); BufferedInputStream bufr = new BufferedInputStream(new FileInputStream("abc.jpg")); OutputStream out = s.getOutputStream(); int len=0; byte[] buf = new byte[1024]; while((len=bufr.read(buf))!=-1) out.write(buf,0,len); s.shutdownOutput(); InputStream in = s.getInputStream(); byte[] bufIn = new byte[1024]; int num = in.read(bufIn); System.out.println(new String(bufIn,0,num)); bufr.close(); s.close(); } }
class PicServer2 { public static void main(String[] args)throws Exception { ServerSocket ss= new ServerSocket(9980); while (true) { Socket s = ss.accept(); new Thread(new PicThread(s)).start(); } } }
class PicThread implements Runnable { private Socket s; public PicThread(Socket s){ this.s = s; } public void run() { int count = 0; try { String ip = s.getInetAddress().getHostAddress(); System.out.println(ip+"。。连接成功"); File file = new File(ip+"("+(count)+")"+".jpg"); while(file.exists()) file = new File(ip+"("+(count++)+")"+".jpg"); InputStream in = s.getInputStream(); FileOutputStream fos = new FileOutputStream(file); byte[] buf = new byte[1024]; int len = 0; while((len=in.read(buf))!=-1){ fos.write(buf,0,len); } OutputStream out = s.getOutputStream(); out.write("上传成功".getBytes()); fos.close(); s.close(); } catch (Exception e) { throw new RuntimeException("上传失败"); } } }
10.可以使用浏览器登录下面的服务端,也可以用telnet远程登录命令
class ServerDemo { public static void main(String[] args)throws Exception { //自定义服务端,使用浏览器登录 ServerSocket ss = new ServerSocket(10000); System.out.println("启动成功"); Socket s = ss.accept(); System.out.println("接收到"+s.getInetAddress().getHostAddress()); PrintWriter pw = new PrintWriter(s.getOutputStream(),true); pw.println("<font color='red'>客户端你好</font>"); s.close(); ss.close(); } }
11.可以自定义浏览器
浏览器软件的强大之处在于包含了很多解析引擎,比如Html解析引擎、CSS解析引擎、JavaScript解析引擎。
浏览器会首先向服务器发生一个头文件:
//chrome浏览器发送的 GET / HTTP/1.1 Host: 127.0.0.1:10000 Connection: keep-alive Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36 Accept-Encoding: gzip, deflate, sdch Accept-Language: zh-CN,zh;q=0.8 //IE浏览器发送的 GET / HTTP/1.1 Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, */* Accept-Language: zh-CN User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Win64; x64; Trident/4.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E; Media Center PC 6.0; Tablet PC 2.0) UA-CPU: AMD64 Accept-Encoding: gzip, deflate Host: 127.0.0.1:10000 Connection: Keep-Alive -------------------------------
Http现在有2个版本,1.1是最新版本。
Keep-Alive表示IE与服务器之间会一直保持连接,但是如果一段时间没有响应,会超时,自动断开连接。 也可以设置为 closed
下面是自己实现的简单IE:
public class MyIE { public static void main(String[] args)throws Exception { // Socket s = new Socket("127.0.0.1",8080); PrintWriter wr = new PrintWriter(s.getOutputStream(),true); wr.println("GET /tyh/demo.html HTTP/1.1"); wr.println("Accept:*/*"); wr.println("Accept-Language: zh-CN"); wr.println("Host: 127.0.0.1:8080"); wr.println("Connection: Keep-Alive"); //这里必须跟2个空行! 这是请求头消息的结束格式 wr.println(); wr.println(); BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream())); String line = null; while((line=bufr.readLine())!=null) System.out.println(line); s.close(); }
连接TomCat服务器之后,服务器也会发一个头消息:
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Accept-Ranges: bytes ETag: W/"7247-1422441251130" Last-Modified: Wed, 28 Jan 2015 10:34:11 GMT Content-Type: text/html Content-Length: 7247 Date: Tue, 24 Feb 2015 09:27:16 GMT
200是响应状态码,代表ok。
12.URL类:
- URL组成: 协议名://服务器名称(或IP地址):端口号/路径和文件名?查询
- URL 可选择指定一个“端口”,它是用于建立到远程主机 TCP 连接的端口号。如果未指定该端口号,则使用协议默认的端口。例如,http 协议的默认端口为 80。
URL的常见构造方式:
URL(String spec)
URL(String protocol, String host, int port, String file)
URL(String protocol, String host, String file)
URL url = new URL("http://cart.mi.com/cart/?你是谁?"); System.out.println(url.getProtocol());//http System.out.println(url.getHost());//cart.mi.com System.out.println(url.getPort());//-1 System.out.println(url.getPath());///cart/ System.out.println(url.getFile());///cart/?你是谁? System.out.println(url.getQuery());//你是谁?
URLConnection类是一个抽象类
- 它是所有表示应用程序与URL之间通信连接的类的父类(super class),该类的实例可以用来对由URL引用的资源进行读取和写入操作。
- 它工作在应用层,将服务器发回的Http协议头信息隐藏
- 它提供了方法,可以查看服务器发回的头信息
- URLConnection类底层依赖Socket类实现网络连接,它比Socket类提供了更便利的网络连接抽象
URL url2 = new URL("http://127.0.0.1:8080/tyh/demo.html"); URLConnection openConnection = url2.openConnection(); System.out.println(openConnection); InputStream in = openConnection.getInputStream(); //打印 sun.net.www.protocol.http.HttpURLConnection:http://www.bjt.name/2013/09/emacs-configure/ //也可以用in = url2.openStream() //该方法是下面方法的缩写: openConnection().getInputStream() byte[] buf = new byte[1024]; int len = in.read(buf); System.out.println(new String(buf,0,len)); in.close();
13.当向浏览器输入一个地址时,浏览器先将地址解析一下,得到服务器名,一般输入的服务器名是域名(Domain Name),如:www.baidu.com
必须先将域名解析成ip地址,需要域名解析服务器(DNS)。
解析之前,会先搜索C:WindowsSystem32driversetc下的hosts文件,查看是否匹配,然后再去查询DNS服务器。
一个IP地址可以对应多个域名,一个域名也可以对应多个IP地址。