网络编程
OSI模型
网络编程主要针对传输层
主要TCP,UDP,IP协议
IP地址
ip地址:InetAddress
-
唯一定位一台网络上的计算机
-
127.0.0.1 本机localhost
-
ip地址分类
ipv4/ipv6
ip4: 127.0.0.1 四个字节的组成
ip6:fe80::2a2d:4550:29e5:66ee%14 128位 8个无符号整数
公网(互联网)-私网(局域网)
192.168.xx.xx 一般都是局域网
IP地址由四段组成,每个字段是一个字节,8位,最大值是255,
IP地址由两部分组成,即网络地址和主机地址。网络地址表示其属于互联网的哪一个网络,主机地址表示其属于该网络中的哪一台主机。二者是主从关系。
IP地址的四大类型标识的是网络中的某台主机。IPv4的地址长度为32位,共4个字节,但实际中我们用点分十进制记法。
IP地址根据网络号和主机号来分,分为A、B、C三类及特殊地址D、E。 全0和全1的都保留不用。
A类:(1.0.0.0-126.0.0.0)(默认子网掩码:255.0.0.0或 0xFF000000)第一个字节为网络号,后三个字节为主机号。该类IP地址的最前面为“0”,所以地址的网络号取值于1~126之间。一般用于大型网络。
B类:(128.0.0.0-191.255.0.0)(默认子网掩码:255.255.0.0或0xFFFF0000)前两个字节为网络号,后两个字节为主机号。该类IP地址的最前面为“10”,所以地址的网络号取值于128~191之间。一般用于中等规模网络。
C类:(192.0.0.0-223.255.255.0)(子网掩码:255.255.255.0或 0xFFFFFF00)前三个字节为网络号,最后一个字节为主机号。该类IP地址的最前面为“110”,所以地址的网络号取值于192~223之间。一般用于小型网络。
D类:是多播地址。该类IP地址的最前面为“1110”,所以地址的网络号取值于224~239之间。一般用于多路广播用户[1]
-
在IP地址3种主要类型里,各保留了3个区域作为私有地址,其地址范围如下: A类地址:10.0.0.0~10.255.255.255 B类地址:172.16.0.0~172.31.255.255 C类地址:192.168.0.0~192.168.255.255
域名:
记忆IP问题!
代码:
package Intel.ip.lesson01; import java.net.InetAddress; import java.net.UnknownHostException; //测试Ip public class TestInetAddress { public static void main(String[] args) { try { //查询本机地址 InetAddress byName = InetAddress.getByName("127.0.0.1"); System.out.println(byName); InetAddress byName3 = InetAddress.getByName("localhost"); System.out.println(byName3); InetAddress byName4 = InetAddress.getLocalHost(); System.out.println(byName4); //查询网站ip地址 InetAddress byName2 = InetAddress.getByName("www.baidu.com"); System.out.println(byName2); //常用方法 System.out.println(byName2.getAddress()); System.out.println(byName2.getCanonicalHostName());//规范的名字 System.out.println(byName2.getHostAddress());//ip System.out.println(byName2.getHostName());//域名,或者自己电脑的名字 } catch (UnknownHostException e) { e.printStackTrace(); } } }
端口
端口表示计算机上一个程序的进程;
-
不同的进程有不同的端口,用来区分软件
-
被规定0-65535
-
TCP,UDP:65535*2 tcp:80 udp:80 单个协议下的端口不能冲突
-
端口分类
-
公有端口:0-1023
-
HTTP:80
-
HTTPS:443
-
FTP:21
-
Telent:23
-
-
程序注册端口:1024-49151 分配用户或者程序
-
Tomcat:8080
-
MySQL:3306
-
Oracle:1521
-
-
动态,私有:49152-65535
netstat -ano #查看所有端口 netstat -ano|findstr "5900" #查看指定的端口 tasklist|findstr "8696" #查看对应端口的进程
-
package Intel.ip.lesson01; import java.net.InetSocketAddress; public class TestInetSocketAddress { public static void main(String[] args) { InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1",8080); InetSocketAddress inetSocketAddress2 = new InetSocketAddress("localhost",8080); System.out.println(inetSocketAddress); System.out.println(inetSocketAddress2); System.out.println(inetSocketAddress.getAddress()); System.out.println(inetSocketAddress.getHostName()); System.out.println(inetSocketAddress.getPort());//端口 System.out.println(inetSocketAddress.getAddress()); } }
-
端口映射:
-
通信协议
TCP/IP协议簇:实际是一组协议
分层思想
重要:
TCP:用户传输协议
UDP:用户数据报协议
IP:网络互联协议
TCP是典型的可靠传输,而UDP则是不可靠传输
TCP建立连接需要三次握手,断开连接需要四次挥手
三次握手简单解:
客户端发送请求给用户端 客户端状态改变进入 SYN_SENT 发送的信息SYN被标志为1
用户端发送请求给客户端 用户端状态改变进入 SYN_RCVD 状态 用户端发送的请求为: SYN+ACK帧
客户端发送请求给用户端 客户端状态改变进入 ESTABLISHED
四次挥手简单解释
1)主动--》被动 主动方已经没有数据要发送但是还可以接受数据
2)被动---》主动 被动方这时候还可以发送数据给主动方,表示自己已经知道主动方只能接受数据不会在发送数据
3)被动----》主动 当被动方数据发送完成,没有数据要发送给主动方时,发送响应报文给主动方,告诉自己没有数据要发送给你了,被动方状态改变
4)主动----》被动 主动方发送的确认响应报文,自己进入TIME_WAIT状态,等待时间内没有接受到其他报文就证明对方已经正常关闭,自己也最终关闭
详细:
(1)第一次挥手:主动断开方(可以是客户端,也可以是服务器端),向对方发送一个FIN结束请求报文,此报文的FIN位被设置为1,并且正确设置Sequence Number(序列号)和Acknowledgment Number(确认号)。发送完成后,主动断开方进入FIN_WAIT_1状态,这表示主动断开方没有业务数据要发送给对方,准备关闭SOCKET连接了。
(2)第二次挥手:正常情况下,在收到了主动断开方发送的FIN断开请求报文后,被动断开方会发送一个ACK响应报文,报文的Acknowledgment Number(确认号)值为断开请求报文的Sequence Number (序列号)加1,该ACK确认报文的含义是:“我同意你的连接断开请求”。之后,被动断开方就进入了CLOSE-WAIT(关闭等待)状态,TCP协议服务会通知高层的应用进程,对方向本地方向的连接已经关闭,对方已经没有数据要发送了,若本地还要发送数据给对方,对方依然会接受。被动断开方的CLOSE-WAIT(关闭等待)还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
主动断开方在收到了ACK报文后,由FIN_WAIT_1转换成FIN_WAIT_2状态。
(3)第三次挥手:在发送完成ACK报文后,被动断开方还可以继续完成业务数据的发送,待剩余数据发送完成后,或者CLOSE-WAIT(关闭等待)截止后,被动断开方会向主动断开方发送一个FIN+ACK结束响应报文,表示被动断开方的数据都发送完了,然后,被动断开方进入LAST_ACK状态。
(4)第四次挥手:主动断开方收在到FIN+ACK断开响应报文后,还需要进行最后的确认,向被动断开方发送一个ACK确认报文,然后,自己就进入TIME_WAIT状态,等待超时后最终关闭连接。处于TIME_WAIT状态的主动断开方,在等待完成2MSL的时间后,如果期间没有收到其他报文,则证明对方已正常关闭,主动断开方的连接最终关闭。
被动断开方在收到主动断开方的最后的ACK报文以后,最终关闭了连接,自己啥也不管了。
TCP协议详解 (史上最全)_tcp协议有哪些_chentiebo的博客-CSDN博客^v88^control_2,239^v2^insert_chatgpt&utm_term=%E9%80%9A%E4%BF%A1%E5%8D%8F%E8%AE%AETcp&spm=1018.2226.3001.4187
TCP编程
客户端
1.连接服务器Socket
2.发送信息
package Intel.ip.lesson02; import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; //客户端 public class TcpClientDemo01 { public static void main(String[] args) throws IOException { Socket socket = null; OutputStream os = null; //1.要知道服务端的地址,和端口号 try { InetAddress serverIP = InetAddress.getByName("127.0.0.1"); //端口号 int port=9999; //2.创建一个socket连接 socket = new Socket(serverIP,port); //3.发送信息 IO流 os = socket.getOutputStream(); os.write("欢迎光临".getBytes(StandardCharsets.UTF_8)); } catch (Exception e) { e.printStackTrace(); }finally { if(os!=null){ os.close(); } if (socket!=null){ socket.close(); } } } }
服务端:
1.建立服务的端口ServerSocket
2.等待用户的连接
3.接受用户信息
package Intel.ip.lesson02; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; //服务端 public class TcpServerDemo01 { public static void main(String[] args) { ServerSocket serverSocket = null; Socket socket = null; InputStream is = null; ByteArrayOutputStream baos = null; try { //1.自己服务端的地址 serverSocket = new ServerSocket(9999); while (true){ //2.等待客户端连接过来 socket = serverSocket.accept(); //3.读取客户端的信息 is = socket.getInputStream(); /* 字符流写法 不推荐 如果是中文超出1024范围会乱码 byte[] bytes = new byte[1024]; int len; while ((len=is.read(bytes))!=-1){ String msg = new String(bytes,0,len); } System.out.println(msg); */ //管道流 baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len=is.read(buffer))!=-1){ baos.write(buffer,0,len); } System.out.println(baos.toString()); } } catch (IOException e) { e.printStackTrace(); }finally { //关闭资源 if (baos!=null){ try { baos.close(); } catch (IOException e) { e.printStackTrace(); } } if (is!=null){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket!=null){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if (serverSocket!=null){ try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
TCP文件上传
服务器端
package Intel.ip.lesson02; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.nio.charset.StandardCharsets; public class TcpServerDemo02 { public static void main(String[] args) throws IOException { //1.创建服务 ServerSocket serverSocket = new ServerSocket(9000); //2.监听客户端的连接 Socket socket = serverSocket.accept();//阻塞式监听,会一直等待客户端的连接 //获取输入流 InputStream is = socket.getInputStream(); //文件输出 FileOutputStream fos = new FileOutputStream(new File("receive.jpg")); byte[] buffer = new byte[1024]; int len; while ((len=is.read(buffer))!=-1){ fos.write(buffer,0,len); } //通知客户端我接受完毕 OutputStream os = socket.getOutputStream(); os.write("服务端接受完毕,可以断开".getBytes(StandardCharsets.UTF_8)); //关闭资源 fos.close(); is.close(); socket.close(); serverSocket.close(); } }
客户端
package Intel.ip.lesson02; import java.io.*; import java.net.InetAddress; import java.net.Socket; public class TcpClientDemo02 { public static void main(String[] args) throws Exception{ //1.创建一个Socket连接 Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9000); //2.创建一个输出流 OutputStream os = socket.getOutputStream(); //3.读取文件 FileInputStream fis = new FileInputStream(new File("E:\\idealearn\\javase\\javaselearn\\src\\1.jpg")); //4.写出文件 byte[] buffer = new byte[1024]; int len; while ((len= fis.read(buffer))!=-1){ os.write(buffer,0,len); } //通知服务端我已经传输完了 socket.shutdownOutput(); //确定服务器接受完毕,才能断开连接 InputStream inputStream = socket.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer2 = new byte[2048]; int len2; while ((len2=inputStream.read(buffer2))!=-1){ baos.write(buffer2,0,len2); } System.out.println(baos.toString()); //5.关闭资源 baos.close(); inputStream.close(); fis.close(); os.close(); socket.close(); } }
Tomcat服务器
UDP
不需要连接
发送端
package Intel.ip.lesson03; import java.net.*; //测试UDP,不需要连接的服务器 public class UpdClientDemo01 { public static void main(String[] args) throws Exception { //1.建立一个Socket DatagramSocket socket = new DatagramSocket(); //2.建一个包 String msg = "你好,服务器"; InetAddress localhost = InetAddress.getByName("localhost"); int port = 9090; //数据 数据长度的起始位置 要发送的对象 DatagramPacket packet = new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,localhost,port); //3.发送包 socket.send(packet); //关闭流 socket.close(); } }
接受端
package Intel.ip.lesson03; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; //还是要等待客户端的链接 public class UpdServerDemo01 { public static void main(String[] args) throws Exception { //开放端口 DatagramSocket socket = new DatagramSocket(9090); //接受数据包 byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length); socket.receive(packet);//阻塞接受 System.out.println(packet.getAddress().getHostAddress()); System.out.println(new String(packet.getData(),0, packet.getLength())); //关闭连接 socket.close(); } }
循环发送信息
发送方:
package Intel.ip.chat; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; public class UdpSenderDemo01 { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(8888); //准备数据 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); while (true){ String data = reader.readLine(); byte[] datas = data.getBytes(StandardCharsets.UTF_8); DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666)); socket.send(packet); if (data.equals("bye")){ break; } } socket.close(); } }
接受方
package Intel.ip.chat; import java.net.DatagramPacket; import java.net.DatagramSocket; public class UdpReceiveDemo01 { public static void main(String[] args) throws Exception { DatagramSocket socket = new DatagramSocket(6666); while (true){ //准备接受包裹 byte[] container = new byte[1024]; DatagramPacket packet = new DatagramPacket(container,0,container.length); socket.receive(packet);//阻塞式接受包裹 //断开连接 byte[] data = packet.getData(); String receiveData = new String(data, 0, packet.getLength()); System.out.println(receiveData); if (receiveData.equals("bye")){ break; } }socket.close(); } }
在线咨询,两个人都可以是发送方,也都可以是接受方
代码实例
package Intel.ip.chat; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketException; import java.nio.charset.StandardCharsets; public class TalkSend implements Runnable { DatagramSocket socket = null; BufferedReader reader = null; private String toIP; private int toPort; private int fromPort; public TalkSend(){ } public TalkSend(String toIP, int toPort, int fromPort) { this.toIP = toIP; this.toPort = toPort; this.fromPort = fromPort; try { socket = new DatagramSocket(fromPort); reader = new BufferedReader(new InputStreamReader(System.in)); } catch (SocketException e) { e.printStackTrace(); } } @Override public void run() { //准备数据 while (true){ String data = null; try { data = reader.readLine(); byte[] datas = data.getBytes(StandardCharsets.UTF_8); DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress(this.toIP,this.toPort)); socket.send(packet); if (data.equals("bye")){ break; } } catch (IOException e) { e.printStackTrace(); } } socket.close(); } }
package Intel.ip.chat; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; public class TalkReceive implements Runnable{ DatagramSocket socket = null; int port; private String msgFrom; public TalkReceive(int port,String msgFrom) { this.port = port; this.msgFrom = msgFrom; try { socket = new DatagramSocket(port); } catch (SocketException e) { e.printStackTrace(); } } @Override public void run() { while (true){ try { //准备接受包裹 byte[] container = new byte[1024]; DatagramPacket packet = new DatagramPacket(container,0,container.length); socket.receive(packet);//阻塞式接受包裹 //断开连接 byte[] data = packet.getData(); String receiveData = new String(data, 0, packet.getLength()); System.out.println(msgFrom+"说:"+receiveData); if (receiveData.equals("bye")){ break; } } catch (IOException e) { e.printStackTrace(); } }socket.close(); } }
package Intel.ip.chat; public class TalkTeacher { public static void main(String[] args) { new Thread(new TalkSend("localhost",8181,5555)).start(); new Thread(new TalkReceive(9191,"学生")).start(); } }
package Intel.ip.chat; public class TalkStudent { public static void main(String[] args) { new Thread(new TalkSend("localhost",9191,7777)).start(); new Thread(new TalkReceive(8181,"老师")).start(); } }
URL
统一资源定位符,定位互联网上的某一个资源
DNS 域名解析 把域名解析为ip
1协议://ip地址 : 端口/项目名/对应的资源
package Intel.ip.lesson04; import java.net.MalformedURLException; import java.net.URL; public class URLDemo01 { public static void main(String[] args) throws MalformedURLException { URL url = new URL("http://localhost:8080/helloworld/index.jsp?uesername=song&password=123"); System.out.println(url.getProtocol());//协议 System.out.println(url.getHost());//ip System.out.println(url.getPort());//端口 System.out.println(url.getPath());//文件 System.out.println(url.getFile());//文件全路径 System.out.println(url.getQuery());//参数 } }
通过url下载资源
package Intel.ip.lesson04; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; public class URLDown { public static void main(String[] args) throws Exception { // 下载地址 URL url = new URL("https://m801.music.126.net/20230713185811/d9f47edd78c1018752375ef15390775c/jdyyaac/obj/w5rDlsOJwrLDjj7CmsOj/29234809622/464f/4b97/8bcd/844b58951a613b79ef18cd7c10cb1111.m4a"); //连接到这个资源 HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); InputStream inputStream = urlConnection.getInputStream(); FileOutputStream fos = new FileOutputStream("11.m4a"); byte[] buffer = new byte[1024]; int len; while ((len=inputStream.read(buffer))!=-1){ fos.write(buffer,0,len); } fos.close(); inputStream.close(); urlConnection.disconnect(); } }