网络编程
1、概述(自行百度)
-
计算机网络:
-
网络协议:就比如说我们规定普通话为通用交流语言,这就是一种协议
-
网络编程的目的:数据交换,通信
2、网络通信的要素
-
IP:定位到网络中的某台计算机
-
端口号:定位到计算机中的某个应用
-
TCP/IP参考模型:(百度上都有)
总结:
1、网络编程中有两个主要问题
a.如何准确的定位到网络上的一台或者多台主机
b.找到主机后如何进行通信
2、网络编程中的要素:IP、端口号、网络通信协议(tcp、udp)
3、万物皆对象
3、IP地址
3.1 分类
-
ipv4 / ipv6:
ipv4:由4个字节组成,0-255, 总共42亿个,如下:
192.168.1.56
ipv6:128位,由8个无符号整数组成,如下:
2408:8207:7895:8e10:bab1:b5ed:7ec6:c2a7
-
公网(互联网)-私网(局域网):
ABCD类地址:
192.168.xx.xx:专门给组织内部使用
-
域名:
3.2 InetAddress对象
-
获取本机IP
//获取本机地址 InetAddress localHost = InetAddress.getLocalHost(); System.out.println(localHost); InetAddress byName = InetAddress.getByName("localhost"); System.out.println(byName); System.out.println(InetAddress.getByName("127.0.0.1"));
-
获取远程IP
//获取百度IP InetAddress baiduIP = InetAddress.getByName("www.baidu.com");
4、端口
-
端口号的范围:0-65535,TCP和UDP都是这个范围
-
常见端口号:HTTP 80、HTTPS 443、FTP 21、Telent 23、Tomcat 8080、Mysql 3306、Oracle 1521
-
端口分类:
-
公有端口:0-1023
-
程序注册端口:1024-49151,分配用户或者程序使用
-
动态、私有:49152-65535`
netstat -ano #查看所有的端口
netstat -ano | grep "1234" #查看指定端口
-
5、通信协议
-
协议:一种约定,比如普通话就是一种交流的协议
-
TCP与UDP:
1、TCP:面相链接、可靠传输、三次握手、四次挥手、点到点传输、数据传输按序到达且不会重复和丢包、效率较低、面相字符传输、首部开销20-60字节
2、UDP:无连接、不可靠、传输数据无序且可能会丢包,、支持一对一,一对多,多对一,多对多等、面向报文传输、首部开销8个字节
-
三次握手:
-
客户端向服务器发送带有SYN标志的数据包(服务器确认客户端的发送和自己接收正常)
-
服务器向客户端发送带有ACK/SYN标志的数据包(客户端确认自己的发送和接收正常,确认服务器的发送和接收正常)
-
客户端向服务器发送带有ACK标志的数据包(服务器确认自己的发送正常和客户端的接收正常)
-
-
四次挥手:
-
客户端向服务器发送带一个FIN,用来关闭客户端到服务器的数据传送
-
服务器接收到FIN并发回一个ack,确认序号为收到的序号加1,和SYN一样,一个FIN将占用一个序号
-
服务器关闭与客户端的链接,发送一个FIN给客户端
-
客户端发回ack报文确认,并将确认序号设置为接受序号加1
-
6、TCP
-
客户端:
-
获取服务器的IP和端口号
-
创建Socket链接
-
通过IO流向服务器发送数据
//获取服务器的IP和端口号 InetAddress address = InetAddress.getByName("127.0.0.1"); int port = 9090; //创建Socket链接 socket = new Socket(address, port); //发送消息通过IO流 outputStream = socket.getOutputStream(); outputStream.write("Hello world!".getBytes());
-
-
服务器
-
设置服务器端口号
-
监听客户端链接(accept)
-
获取客户端信息
-
处理信息
//设置服务端端口号为9090 serverSocket = new ServerSocket(9090); while (true){ //监听客户端链接 socket = serverSocket.accept(); //获取客户端的消息 inputStream = socket.getInputStream(); /* //处理inputstream byte[] buffer = new byte[1024]; int len; while((len = inputStream.read(buffer)) != -1){ String msg = new String(buffer, 0, len); System.out.println(msg); }*/ //通过管道流处理inputstream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] bytes = new byte[1024]; int len; while((len = inputStream.read(bytes)) != -1){ byteArrayOutputStream.write(bytes, 0, len); } System.out.println(byteArrayOutputStream.toString()); }
-
-
文件上传
服务器端
public class TCPDownload { private static ServerSocket serverSocket = null; private static Socket socket = null; private static InputStream inputStream = null; private static FileOutputStream fileOutputStream = null; private static OutputStream outputStream = null; public static void main(String[] args) { try { serverSocket = new ServerSocket(8888); socket = serverSocket.accept(); inputStream = socket.getInputStream(); fileOutputStream = new FileOutputStream(new File("receive.jpg")); byte[] buffer = new byte[1024]; int len; while((len = inputStream.read(buffer)) != -1){ fileOutputStream.write(buffer, 0, len); } //当服务器接受完毕后,告知客户端接受完毕 outputStream = socket.getOutputStream(); outputStream.write("upload success!".getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { //关闭资源(自己封装的关闭资源的工具类) CloseResource.closeResource(fileOutputStream); CloseResource.closeResource(inputStream); CloseResource.closeResource(socket); CloseResource.closeResource(serverSocket); } } }
客户端
public class TCPUpload { private static Socket socket = null; private static OutputStream outputStream = null; private static FileInputStream fileInputStream = null; private static InputStream inputStream = null; private static ByteArrayOutputStream byteArrayOutputStream = null; public static void main(String[] args) { try { //获取服务器IP和端口号,这里我们使用本机作为服务器 InetAddress localhost = InetAddress.getByName("localhost"); int port = 8888; socket = new Socket(localhost, port); outputStream = socket.getOutputStream(); //读取文件 fileInputStream = new FileInputStream("/home/lpf/图片/man_paint_sky_129261_1920x1080.jpg"); //写文件 byte[] buffer = new byte[1024]; int len; while((len = fileInputStream.read(buffer)) != -1){ outputStream.write(buffer, 0, len); } //通知服务器我已经传送完毕了 socket.shutdownOutput(); //如果不写这句代码,客户端和服务器都会处在一个无限等待的状态 //获取服务端的通知 inputStream = socket.getInputStream(); byteArrayOutputStream = new ByteArrayOutputStream(); byte[] bytes = new byte[1024]; int length; while((length = inputStream.read(bytes)) != -1){ byteArrayOutputStream.write(bytes, 0, length); } System.out.println(byteArrayOutputStream.toString()); } catch (IOException e) { e.printStackTrace(); } finally { //关闭资源的工具类 CloseResource.closeResource(byteArrayOutputStream); CloseResource.closeResource(inputStream); CloseResource.closeResource(fileInputStream); CloseResource.closeResource(outputStream); CloseResource.closeResource(socket); } } }
-
Tomcat用来做服务端(了解即可)
7、UDP
比如发短信的时候,我不需要与对方进行链接,只需要知道对方的地址即可
-
发送端
public class UDPClient { private static DatagramSocket datagramSocket = null; private static DatagramPacket datagramPacket = null; public static void main(String[] args) { try { //创建一个Socket datagramSocket = new DatagramSocket(); //获取服务端的IP和端口号 InetAddress address = InetAddress.getByName("127.0.0.1"); int port = 9090; //设置发送的消息 String msg = "Hello world!"; //创建数据包 datagramPacket = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, address, port); //发送包 datagramSocket.send(datagramPacket); } catch (IOException e) { e.printStackTrace(); } finally { CloseResource.closeResource(datagramPacket); CloseResource.closeResource(datagramSocket); } } }
-
接收端
public class UDPServer { private static DatagramSocket datagramSocket = null; private static DatagramPacket datagramPacket = null; public static void main(String[] args) { try { datagramSocket = new DatagramSocket(9090); byte[] buffer = new byte[1024]; datagramPacket = new DatagramPacket(buffer, 0, buffer.length); datagramSocket.receive(datagramPacket); //输出包中的信息 System.out.println(datagramPacket.getAddress()); System.out.println(new String(datagramPacket.getData(), 0, datagramPacket.getLength())); } catch (IOException e) { e.printStackTrace(); } finally { CloseResource.closeResource(datagramPacket); CloseResource.closeResource(datagramSocket); } } }
-
使用UDP实现端到端的聊天Demo(使用多线程,参照上面代码)
发送方:
public class UDPSend implements Runnable { private DatagramSocket socket = null; private BufferedReader reader = null; private int fromPort; private int toPort; private String toIP; public UDPSend(int fromPort, int toPort, String toIP) { this.fromPort = fromPort; this.toPort = toPort; this.toIP = toIP; try { socket = new DatagramSocket(this.fromPort); reader = new BufferedReader(new InputStreamReader(System.in)); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { while (true){ try { byte[] data = reader.readLine().getBytes(); DatagramPacket packet = new DatagramPacket(data, 0, data.length, new InetSocketAddress(toIP, toPort)); socket.send(packet); if ("bye".equals(new String(data, 0, data.length))) { break; } } catch (IOException e) { e.printStackTrace(); } } socket.close(); } }
接受方:
public class UDPRevice implements Runnable { private DatagramSocket socket = null; private int fromPort; private String myName; public UDPRevice(int fromPort, String myName) { this.fromPort = fromPort; this.myName = myName; try { socket = new DatagramSocket(fromPort); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { while (true){ try{ byte[] data = new byte[1024]; DatagramPacket packet = new DatagramPacket(data, 0, data.length); socket.receive(packet); byte[] msg = packet.getData(); String receiveData = new String(msg, 0, msg.length); System.out.println(myName + ":" + receiveData); if ("bye".equals(receiveData)) { break; } } catch (IOException e) { e.printStackTrace(); } } socket.close(); } }
最后通代理模式创建这两个线程从而实现聊天功能:
public class TalkStudent { public static void main(String[] args) { new Thread(new UDPSend(7777, 9999, "127.0.0.1")).start(); new Thread(new UDPRevice(8888, "Teacher")).start(); } }
8、URL
-
统一资源定位符
-
组成:
协议://IP地址:端口/项目名/资源
-
下载网络资源
public class DownloadURL { private static HttpURLConnection connection = null; private static InputStream inputStream = null; private static FileOutputStream stream = null; public static void main(String[] args) { try { URL url = new URL("https://m701.music.126.net/20211019180445/4bd82af769d78f834d6c47666191b513/jdyyaac/obj/w5rDlsOJwrLDjj7CmsOj/11255785312/2660/3c23/c8a7/9d1782c01855c2d620a6afcbdfab6bd9.m4a"); //链接资源 connection = (HttpURLConnection)url.openConnection(); //获取流并下载 inputStream = connection.getInputStream(); stream = new FileOutputStream("f.m4a"); byte[] data = new byte[1024]; int len; while((len = inputStream.read(data)) != -1){ stream.write(data, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { connection.disconnect(); CloseResource.closeResource(inputStream); CloseResource.closeResource(stream); } } }
笔记是按照B站狂神的视频写的