网络编程学习笔记(未完结)
IP地址,端口,URL:
IP地址:用来标识网络中的一个通信实体的地址。通信实体可以是计算机、路由器等。 比如互联网的每个服务器都要有自己的IP地址,而每个局域网的计算机要通信也要配置IP地址。路由器是连接两个或多个网络的网络设备。目前主流使用的IP地址是IPV4,但是随着网络规模的不断扩大,IPV4面临着枯竭的危险,所以推出了IPV6。
用InetAddress类可以创建本机或者利用域名/IP地址来创建对象,并通过getHostAddress(),getHostName()获取对象信息。
1 InetAddress addr1 = InetAddress.getLocalHost();//为本机创建对象 2 System.out.println(addr1.getHostAddress());//获取本机IP地址 3 System.out.println(addr1.getHostName()); //获取本机名字 4 System.out.println("----------------------------------"); 5 6 InetAddress addr2 = InetAddress.getByName("www.163.com");//为163创建对象,从名字来获取信息 7 System.out.println(addr2.getHostAddress());//获取163IP地址 8 System.out.println(addr2.getHostName()); //获取163域名 9 System.out.println("----------------------------------"); 10 11 InetAddress addr3 = InetAddress.getByName("112.13.210.199");//为163创建对象,从名字来获取信息 12 System.out.println(addr3.getHostAddress());//获取163IP地址 13 System.out.println(addr3.getHostName()); //输出的也是IP地址
端口:IP地址用来标识一台计算机,但是一台计算机上可能提供多种网络应用程序,端口被用来区分这些不同的程序。端口是虚拟的概念,并不是说在主机上真的有若干个端口。通过端口,可以在一个主机上运行多个网络应用程序。 端口的表示是一个16位的二进制整数,对应十进制的0-65535。
用InetSocketAddress类可以利用域名/IP地址+端口号来创建对象,并通过getHostAddress(),getHostName()获取对象信息。
1 InetSocketAddress isa1 = new InetSocketAddress("127.0.0.1",8080); 2 System.out.println(isa1.getHostName()); 3 System.out.println(isa1.getAddress()); 4 5 InetSocketAddress isa2 = new InetSocketAddress("localhost",9000); 6 System.out.println(isa2.getHostName()); 7 System.out.println(isa2.getAddress());
URL:在www上,每一信息资源都有统一且唯一的地址,该地址就叫URL(Uniform Resource Locator),它是www的统一资源定位符。URL由4部分组成:协议 、存放资源的主机域名、资源文件名和端口号。如果未指定该端口号,则使用协议默认的端口。例如http 协议的默认端口为 80。 在浏览器中访问网页时,地址栏显示的地址就是URL。
可用URL类以URL来创建对象,并获取各种信息。以http://www.baidu.com:80/index.html?uname=shsxt&age=18#a为例:
协议:http
域名/IP:www.baidu.com
端口:80
请求资源:/index.html
参数:uname=shsxt&age=18
锚点:a
1 URL url = new URL("http://www.baidu.com:80/index.html?uname=shsxt&age=18#a"); 2 System.out.println("协议-"+url.getProtocol()); 3 System.out.println("域名/IP-"+url.getHost()); 4 System.out.println("端口-"+url.getPort()); 5 System.out.println("请求资源1-"+url.getFile()); 6 System.out.println("请求资源2-"+url.getPath()); 7 System.out.println("参数-"+url.getQuery()); 8 System.out.println("锚点-"+url.getRef());
网络通信协议:
OSI七层协议模型
TCP/IP网络通信协议是OSI模型的具体实现。
TCP协议:
在网络通讯中,TCP方式就类似于拨打电话,使用该种方式进行网络通讯时,需要建立专门的虚拟连接,然后进行可靠的数据传输,如果数据发送失败,则客户端会自动重发该数据。TCP是面向连接的,传输数据安全,稳定,效率相对较低。
TCP(Transfer Control Protocol)是面向连接的,所谓面向连接,就是当计算机双方通信时必需经过先建立连接,然后传送数据,最后拆除连接三个过程。
TCP在建立连接时又分三步走(三次握手Three-way Handshake):
第一步:是请求端(客户端)发送一个包含SYN即同步(Synchronize)标志的TCP报文,SYN同步报文会指明客户端使用的端口以及TCP连接的初始序号。
第二步:服务器在收到客户端的SYN报文后,将返回一个SYN+ACK的报文,表示客户端的请求被接受,同时TCP序号被加一,ACK即确认(Acknowledgement)。
第三步:客户端也返回一个确认报文ACK给服务器端,同样TCP序列号被加一,到此一个TCP连接完成。然后才开始通信的第二步:数据处理。
UDP协议:
称为数据报通信方式。在这种方式中,每个数据发送单元被统一封装成数据报包的方式,发送方将数据报包发送到网络中,数据报包在网络中去寻找它的目的地。
UDP方式就类似于发送短信,使用这种方式进行网络通讯时,不需要建立专门的虚拟连接,传输也不是很可靠,如果发送失败则客户端无法获得。
大量的非核心数据可以通过UDP方式进行传递。 UDP是面向无连接的,传输数据不安全,效率较高。
Socket套接字:
我们开发的网络应用程序位于应用层,TCP和UDP属于传输层协议,在应用层和传输层之间,使用套接Socket来进行分离。
套接字就像是传输层为应用层开的一个小口,应用程序通过这个小口向远程发送数据,或者接收远程发来的数据;而这个小口以内,也就是数据进入这个口之后,或者数据从这个口出来之前,是不知道也不需要知道的,也不会关心它如何传输,这属于网络其它层次工作。
Socket实际是传输层供给应用层的编程接口。Socket就是应用层与传输层之间的桥梁。使用Socket编程可以开发客户机和服务器应用程序,可以在本地网络上进行通信,也可通过Internet在全球范围内通信。
TCP套接字通信双方须链接,且有主次之分。UDP套接字无须链接,通信双方平等。
数据封装与解封:
1.数据发送处理过程
(1)应用层将数据交给传输层,传输层添加上TCP的控制信息(称为TCP头部),这个数据单元称为段(Segment),加入控制信息的过程称为封装。然后,将段交给网络层。
(2)网络层接收到段,再添加上IP头部,这个数据单元称为包(Packet)。然后,将包交给数据链路层。
(3) 数据链路层接收到包,再添加上MAC头部和尾部,这个数据单元称为帧(Frame)。然后,将帧交给物理层。
(4)物理层将接收到的数据转化为比特流,然后在网线中传送。
2.数据接收处理过程
(1)物理层接收到比特流,经过处理后将数据交给数据链路层。
(2)数据链路层将接收到的数据转化为数据帧,再除去MAC头部和尾部,这个除去控制信息的过程称为解封,然后将包交给网络层。
(3)网络层接收到包,再除去IP头部,然后将段交给传输层。
(4)传输层接收到段,再除去TCP头部,然后将数据交给应用层。
网络爬虫:
从网络上获取数据的过程。
1.给一个URL
2.下载资源
3.分析资源(使用正则表达式)
4.操作数据
1,2步程序如下:
利用url创建对象后,用InputStreamReader与readLine()方法下载资源。
1 URL url = new URL("http://www.baidu.com");//给一个url 2 InputStream is = url.openStream();//下载资源 3 BufferedReader br = new BufferedReader(new InputStreamReader(is,"UTF-8")); 4 String msg = null; 5 while(null!=(msg=br.readLine())) { 6 System.out.println(msg); 7 } 8 br.close(); 9 }
有些网站不可直接下载资源,可以用模拟浏览器的方法获取资源:
获取网页UserAgent方法:打开网页,Fn+F12,Network,Headers
1 URL url = new URL("http://www.dianping.com"); 2 HttpURLConnection huc = (HttpURLConnection)url.openConnection(); 3 huc.setRequestMethod("GET"); 4 huc.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.87 Safari/537.36"); 5 BufferedReader br = new BufferedReader(new InputStreamReader(huc.getInputStream(),"UTF-8")); 6 String msg = null; 7 while(null!=(msg=br.readLine())) { 8 System.out.println(msg); 9 } 10 br.close(); 11 }
UDP编程:
每个数据发送单元被统一封装成数据包的方式,发送方将数据包发送到网络中,数据包在网路中去寻找他的目的地。
发送端:
1.使用DatagramSocket指定端口,创建发送端
2.准备数据,转成字节数组
3.封装成DatagramPacket包裹,需要指定目的地
4.发送包裹send(DatagramPacket 对象名称)
5.释放资源
1 System.out.println("发送方启动中..."); 2 //指定端口,创建发送端 3 DatagramSocket client = new DatagramSocket(8888); 4 //将要发送的内容转化为字节数组 5 String data = "努力学习"; 6 byte[] datas = data.getBytes(); 7 //封装成为DatagramPacket包裹,并指定目的地端口 8 DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",9999)); 9 //发送包裹 10 client.send(packet); 11 //释放资源 12 client.close();
接收端:
1.使用DatagramSocket指定端口,创建接收端
2.准备容器,封装成DatagramPacket包裹
3.阻塞式接受包裹receive(DatagramPacket 对象名称)
4.分析数据 byte[ ] getData() getLength()
5.释放资源
1 System.out.println("接收方启动中..."); 2 //指定端口,创建接收端 3 DatagramSocket server = new DatagramSocket(9999); 4 //准备一个容器,并封装成为DatagramPacket包裹 5 byte[] container = new byte[1024*60]; 6 DatagramPacket packet = new DatagramPacket(container,0,container.length); 7 //阻塞式接收包裹 8 server.receive(packet); 9 //分析数据 10 byte[] datas = packet.getData(); 11 int length = packet.getLength(); 12 System.out.println(new String(datas,0,length)); 13 //释放资源 14 server.close();
基本类型数据的发送:
第二步替换为:创建ByteArrayOutputStream流,用DataOutputStream流写入需要发送的内容。将ByteArrayOutputStream流用toByteArray()转化为字节数组。
1 System.out.println("发送方启动中..."); 2 //指定端口,创建发送端 3 DatagramSocket client = new DatagramSocket(8888); 4 //将要发送的内容转化为字节数组 5 ByteArrayOutputStream baos= new ByteArrayOutputStream(); 6 DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos)); 7 dos.writeUTF("努力学习"); 8 dos.writeInt(18); 9 dos.writeBoolean(false); 10 dos.writeChar('a'); 11 dos.flush(); 12 byte[] datas = baos.toByteArray();//转化为字节数组 13 //封装成为DatagramPacket包裹,并指定目的地端口 14 DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",9999)); 15 //发送包裹 16 client.send(packet); 17 //释放资源 18 client.close(); 19 baos.close(); 20 dos.close(); 21
基本类型数据的接收:
第四步替换为:创建ByteArrayOutputStream流,用getData()方法读出数据包中的数据。用DataInputStream流将数据存入,再用readxxx()方法读到各自数据类型变量中,最后打印即可。
1 System.out.println("接收方启动中..."); 2 //指定端口,创建接收端 3 DatagramSocket server = new DatagramSocket(9999); 4 //准备一个容器,并封装成为DatagramPacket包裹 5 byte[] container = new byte[1024*60]; 6 DatagramPacket packet = new DatagramPacket(container,0,container.length); 7 //阻塞式接收包裹 8 server.receive(packet); 9 //分析数据 10 DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(packet.getData())));//读出基本类型 11 String msg = dis.readUTF(); 12 int age = dis.readInt(); 13 Boolean flag = dis.readBoolean(); 14 char ch = dis.readChar(); 15 System.out.println(msg); 16 System.out.println(age); 17 System.out.println(flag); 18 System.out.println(ch); 19 //释放资源 20 server.close(); 21 dis.close();
UTP编程:
创建服务器:
1.指定端口,使用ServerSocket创建服务器。
2.阻塞式等待accept。
3.操作:输入输出流操作。
4.释放资源。
创建客户端:
1.创建Scoket对象,指定要连接的服务器的IP和端口
2.获取scoket的输入流,并使用缓冲流进行包装
3.接收服务器端发送的信息
4.关闭流及socket连接