当前位置: 代码迷 >> 综合 >> Day17,18 网络编程:通信协议(TCP,UDP),IP,端口
  详细解决方案

Day17,18 网络编程:通信协议(TCP,UDP),IP,端口

热度:87   发布时间:2024-02-20 10:48:55.0

网络编程

1.1、概述

地球村:

对地球的一种比喻说法。现代科技的迅速发展,缩小了地球上的时空距离,国际交往日益频繁便利,因而整个地球就如同是茫茫宇宙中的一个小村落。

计算机网络:

是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。

网络编程的目的:

无线电台…传播交流信息,数据交换。通信。

想要达到的效果需要什么:

  1. 如何准确的定位网络上的一台电脑 192.168.16.124:端口,定位到这个计算机上的某个资源。
  2. 找到这个主机,如何传输数据呢?

javaweb:网页编程 BS

网络编程:TCP/IP CS

1.2、网络通信的要素

如何实现网络通信?

需要知道通信双方地址:

  • ip 192.168.1.1
  • 端口号
  • 192.168.16.24:5900

规则:网络通信协议

TCP/IP 参考模型

在这里插入图片描述

小结:

  1. 网络编程中有两个主要问题
    • 如何准确定位到网络上的一台或者多台主机
    • 找到主机之后如何进行通信
  2. 网络编程中的要素
    • ip和端口号 ip
    • 网络通信协议 udp,tcp
  3. 万物皆对象

1.3、IP

ip地址:InetAddress

  • 唯一定位一台计算机

  • 127.0.01:本机localhost

  • ip地址分类

    • ipv4/ipv6地址分类

      • IPV4 127.0.0.1 ,4个字节组成,1个字节8位。0-255,42亿~;30亿都在北美,亚洲4亿,2011年就用尽了。
      • IPV6 fe80::e574:5dfc:4204:8875%11,16个字节,128位。8个无符号整数。
      2001:0bb2:aaa:0015:0000:0000:1aaa:1312
      每个数字都是16进制,一个十六进制数可以写成4个二进制数(就是占4位)。共32个数字*4位=128
      
    • 公网(互联网)-私网(局域网)

      • ABCD类地址

      • 192.168.xx.xx ,专门给组织内部使用的。

  • 域名:记忆IP问题!

    • IP:www.vip.com 万网
import java.net.UnknownHostException;public class TestInetAddress {
    public static void main(String[] args) {
    try {
    //查询本地地址InetAddress byName = InetAddress.getByName("127.0.0.1");System.out.println(byName);//查询网站ip地址InetAddress byName1 = InetAddress.getByName("www.baidu.com");System.out.println(byName1);//常用方法System.out.println(byName1.getAddress());System.out.println(byName1.getCanonicalHostName());//规范的名字System.out.println(byName1.getHostAddress());//ipSystem.out.println(byName1.getHostName());//域名,或者自己的电脑的额名字} catch (UnknownHostException e) {
    e.printStackTrace();}}}

1.4、端口

端口表示计算机上的一个程序的进程。

  • 不同进程有不同的端口号!用来区分软件!

  • 端口被规定范围:0~65535

  • TCP,UDP:这两个都有65535这么多端口,即65535*2。tcp:80,udp:80.单个协议下,端口号不能冲突。

  • 端口分类

    • 公有端口0-1023

      • HTTP默认端口:80
      • HHTPS默认端口:443
      • FTP:21
      • Telent:23
    • 程序注册端口:1024~49151,非陪用户或者程序

      • Tomcat:8080
      • MySQL:3306
      • Oracle:1521
    • 动态、私有:49152-65535

      netstat -ano 命令:可以查看本机开放的全部端口。
      
      • LISTENING时表示处于侦听状态,就是说该端口是开放的,等待连接,但还没有被连接。就像
        你房子的门已经敞开的,但还没有人进来。
      • ESTABLISHED的意思是建立连接。表示两台机器正在通信。
      • CLOSE_WAIT 对方主动关闭连接或者网络 异常导致连接中断。
      • TIME_WAIT 我方主动调用close()断开连接,收到对方确认后状态变为TIME_WAIT。
      netstat -ano|findstr "5900":查看5900端口详情。
      tasklist|findsr "8696" :查看指定端口的进程。(或者电脑任务管理器里面的PID栏查看)
      
      public class TestInetSocktaddress {
              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());//hosts文件可以配置映射地址System.out.println(inetSocketAddress.getPort());//端口}
      }
      

在这里插入图片描述

1.5、通信协议

协议:约定,就好比我们现在说的是普通话。

**网络通信协议:**速率,传输码率,代码结构,传输控制。。。

**问题:**非常的复杂

大事化小:分层!

TCP/IP协议簇:实际上是一组协议

重要:

  • TCP:用户传输协议。
  • UDP:用户数据报协议。

出名的协议:

  • TCP:用户传输协议。
  • IP:网络互联协议。

TCP和UDP对比:

TCP:打电话

  • 连接,稳定
  • 三次握手,四次挥手。
最少需要三次,保证稳定连接!
A:你瞅啥?
B:瞅你咋地?
A:干一场!四次挥手:
A:我要走了
B:你真的要走了吗?
B:你真的真的要走了吗?
A:我真的要走了!

在这里插入图片描述
在这里插入图片描述

  • 客户端,服务端
  • 传输完成,释放连接,效率低

UDP:发短信

  • 不连接,不稳定。
  • 客户端、服务端:没有明确的界限。
  • 不管有没有准备好,都可以发给你。
  • 导弹攻击
  • DDOS:洪水攻击!(饱和攻击)

1.6、TCP

客户端

  1. 连接服务器 Socket
  2. 发送消息
//客户端
public class TcpClientDemo01 {
    public static void main(String[] args) {
    Socket socket=null;OutputStream outputStream=null;try {
    //1.要知道服务器的地址、端口号InetAddress serverIp=InetAddress.getByName("127.0.0.1");int port=9999;//2.创建一个socket连接socket = new Socket(serverIp,port);//3.发送消息 IO流outputStream = socket.getOutputStream();outputStream.write("你好,欢迎学习java".getBytes());} catch (Exception e) {
    e.printStackTrace();}finally {
    if (outputStream!=null){
    try {
    outputStream.close();} catch (IOException e) {
    e.printStackTrace();}}if (socket!=null){
    try {
    socket.close();} catch (IOException e) {
    e.printStackTrace();}}}}
}

服务器

  1. 建立服务端口ServerSocket
  2. 等待用户的连接accept
  3. 接收消息
//服务端
public class TcpServerDemo01 {
    public static void main(String[] args) {
    ServerSocket serverSocket = null;Socket socket = null;InputStream inputStream = null;ByteArrayOutputStream baos = null;try {
    //1.我得有一个地址serverSocket = new ServerSocket(9999);while (true){
    //2.等待客户端连接过来socket = serverSocket.accept();//3.读取客户端的消息inputStream = socket.getInputStream();//管道流baos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len;while ((len = inputStream.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 (inputStream != null) {
    try {
    inputStream.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();}}}}
}

文件上传

//服务端
public class TcpServerDemo02 {
    public static void main(String[] args) {
    ServerSocket serverSocket = null;Socket socket = null;InputStream inputStream = null;FileOutputStream baos = null;OutputStream outputStream = null;try {
    //1.创建服务serverSocket = new ServerSocket(9000);//2.监听客户端连接//阻塞式监听,会一直等待客户端连接socket = serverSocket.accept();//3.读取客户端的消息//获取输入流inputStream = socket.getInputStream();//4.文件输出,利用管道流baos = new FileOutputStream(new File("jyw123.jpg"));byte[] buffer = new byte[1024];int len;//每次读取一个字节while ((len = inputStream.read(buffer)) != -1) {
    baos.write(buffer, 0, len);}//通知客户端接收完毕outputStream = socket.getOutputStream();outputStream.write("我接受完毕了,你可以断开了".getBytes());} catch (IOException e) {
    e.printStackTrace();} finally {
    //关闭资源if (outputStream != null) {
    try {
    outputStream.close();} catch (IOException e) {
    e.printStackTrace();}}if (baos != null) {
    try {
    baos.close();} catch (IOException e) {
    e.printStackTrace();}}if (inputStream != null) {
    try {
    inputStream.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();}}}}
}
//客户端
public class TcpClientDemo02 {
    public static void main(String[] args) {
    //1。创建一个Socket连接Socket socket = null;try {
    socket = new Socket(InetAddress.getByName("127.0.0.1"),9000);//2.创建一个输出流OutputStream outputStream = socket.getOutputStream();//3.文件流FileInputStream fileInputStream = new FileInputStream(new File("F:\\worksapce\\wlbc-study\\src\\123.jpg"));//4.写出文件byte[] buffer = new byte[1024];int len;// read (byte[] b) 方法, 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数。while ((len=fileInputStream.read(buffer))!=-1){
    outputStream.write(buffer,0,len);}//通知服务器,我已经结束了socket.shutdownOutput();//我已经传输完了//确定服务器接收完毕,才能断开连接InputStream inputStream = socket.getInputStream();//String byte[]ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] buffer2 = new byte[2014];int len2;while ((len2=inputStream.read(buffer2))!=-1){
    baos.write(buffer2,0,len2);}System.out.println(baos.toString());//5.关闭资源baos.close();fileInputStream.close();outputStream.close();socket.close();} catch (IOException e) {
    e.printStackTrace();}}
}

Tomcat

服务端

  • 自定义S
  • Tomcat服务器S

客户端

  • 自定义 C
  • 浏览器 B

1.7、UDP

发短信:不用连接,需要知道对方的地址!

发送消息:

public class UdpClientDemo1 {
    public static void main(String[] args) throws Exception {
    //1.建立一个SocketDatagramSocket 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);//4.关闭资源socket.close();}
}

接收消息

//还是要等待客户端的连接!
public class UdpServerDemo1 {
    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();}
}

循环发送消息

public class UdpSendDemo01 {
    public static void main(String[] args) throws Exception {
    DatagramSocket socket = new DatagramSocket(8888);//准备数据:读取控制台Ststem.inBufferedReader reader = new BufferedReader(new InputStreamReader(System.in));while (true) {
    String data = reader.readLine();byte[] dates = data.getBytes();DatagramPacket packet = new DatagramPacket(dates, 0, dates.length, new InetSocketAddress("localhost", 6666));System.out.println(dates.length);//bye:3System.out.println(packet.getLength());//bye:3socket.send(packet);if (data.equals("bye")) {
    break;}}socket.close();}
}

循环接收消息

public class UdpReceiveDemo01 {
    public static void main(String[] args) throws Exception {
    DatagramSocket socket = new DatagramSocket(6666);while (true) {
    //准备接收包裹,放到container里面byte[] container = new byte[1024];System.out.println(container.length);//1024DatagramPacket packet = new DatagramPacket(container, 0, container.length);System.out.println(packet.getLength());//1024socket.receive(packet);//阻塞式接收包裹。上面是1024,下面是3,说明receive方法将他改变了System.out.println(packet.getLength());//3//断开连接bytebyte[] data = packet.getData();//1024//String receiveData = new String(data, 0, data.length);//1024String receiveData = new String(data, 0, packet.getLength());//我不需要固定数组container那么长(1024),我只需要packet里面数据长度(3),这样写后面的equals判断不需要写trim()System.out.println(packet.getLength());//收到的是长度是3System.out.println(data.length);//1024System.out.println(receiveData.length());//3System.out.println(receiveData);if (receiveData.trim().equals("bye")) {
    break;}}socket.close();}
}

在线咨询:两个人都可以发送方,也都可以是接收方!

多线程互相聊天

发送类工具

//发送线程
public class TalkSend implements Runnable{
    DatagramSocket socket =null;BufferedReader reader =null;private String toIp;private int fromPort;private int toPort;public TalkSend(int fromPort,String toIp,  int toPort) {
    this.toIp = toIp;this.fromPort = fromPort;this.toPort = toPort;try {
    socket =new DatagramSocket(fromPort);reader = new BufferedReader(new InputStreamReader(System.in));} catch (Exception e) {
    e.printStackTrace();}}@Overridepublic void run() {
    while (true) {
    try {
    String data = reader.readLine();DatagramPacket packet = new DatagramPacket(data.getBytes(), 0, data.getBytes().length, new InetSocketAddress(this.toIp, this.toPort));socket.send(packet);if (data.equals("bye")) {
    break;}} catch (Exception e) {
    e.printStackTrace();}}socket.close();}
}

接受类工具

//接收线程
public class TalkReceive implements Runnable{
    DatagramSocket socket =null;private 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();}}@Overridepublic void run() {
    while (true) {
    try {
    //准备接收包裹,放到container里面byte[] container = new byte[1024];DatagramPacket packet = new DatagramPacket(container, 0, container.length);socket.receive(packet);//阻塞式接收包裹。上面是1024,下面是3,说明receive方法将他改变了//断开连接byteString receiveData = new String(packet.getData(), 0, packet.getLength());System.out.println(msgFrom+":"+receiveData);if (receiveData.trim().equals("bye")) {
    break;}} catch (IOException e) {
    e.printStackTrace();}}socket.close();}
}

学生端启动类

public class TalkStudent {
    public static void main(String[] args) {
    //开启两个线程new Thread(new TalkSend(7777,"localhost",9999)).start();new Thread(new TalkReceive(8888,"老师")).start();}
}

老师类启动端

public class TalkTeacher {
    public static void main(String[] args) {
    //开启两个线程new Thread(new TalkSend(5555,"localhost",8888)).start();new Thread(new TalkReceive(9999,"学生")).start();}
}

1.8、URL

https://www.baidu.com/

统一资源定位符:定位资源,定位互联网上的某一资源。

DNS域名解析:将https://www.baidu.com/解析成xxx.x…x…x

本质是把域名解析成ip

基本上5部分组成:
协议://IP地址:端口/项目名/对应资源
public class URLDown {
    public static void main(String[] args) throws Exception {
    //1.下载地址URL url = new URL("https://m10.music.126.net/20200919161055/7963703b1af08b9d00a2e6ce2ba6c981/yyaac/obj/wonDkMOGw6XDiTHCmMOi/3918591949/c8a1/cba7/c6ea/5a3677569928db9f736580e5a2107f55.m4a");HttpsURLConnection httpURLConnection=(HttpsURLConnection)url.openConnection();InputStream inputStream = httpURLConnection.getInputStream();FileOutputStream fileOutputStream = new FileOutputStream("f.m4a");byte[] bytes = new byte[1024];int len;if ((len=inputStream.read(bytes))!=-1){
    fileOutputStream.write(bytes,0,len);//写出这个数据}fileOutputStream.close();inputStream.close();httpURLConnection.disconnect();//断开连接}
}