网络编程

网络编程

概述

计算机网络:

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

网络编程的目的:传播交流信息(数据交换、通信)

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

  1. 如何准确的定位网络上的一台主机: IP地址、端口号 ,定位到这个计算机上的某个资源

  2. 找到了这个主机,如何进行传输数据

 

网络编程: TCP/IP 协议 C/S架构

javaweb:网页编程 B/S架构

 

C/S架构: 服务器-客户机( Server-Client ),即C/S结构。C/S结构通常采取两层结构。服务器负责数据的管理,客户机负责完成与用户的交互任务。

 

B/S架构: B/S架构即浏览器和服务器架构模式,是随着Internet技术的兴起,对C/S架构架构/1050735)的一种变化或者改进的架构。在这种架构下,用户工作界面是通过WWW浏览器来实现,极少部分事务,事务逻辑在前端(Browser)实现,但是主要事务逻辑在服务器端(Server)实现,形成所谓三层3-tier结构。B/S架构是WEB兴起后的一种网络架构模式,WEB浏览器是客户端最主要的应用软件。这种模式统一了客户端,将系统功能实现的核心部分集中到服务器上,简化了系统的开发、维护和使用。客户机上只要安装一个浏览器(Browser),如Netscape Navigator或Internet Explorer,服务器安装Oracle、Sybase、Informix或 SQL Server等数据库。浏览器通过Web Server同数据库进行数据交互。 这样就大大简化了客户端电脑载荷,减轻了系统维护与升级的成本和工作量,降低了用户的总体成本(TCO)。

 

网络通信的要素

如何实现网络的通信:

  1. 通信双方地址( ip 端口号 192.168.0.100 139)

    比如:ping百度 可以得到百度服务器的ip地址

     

  2. 规则:网络通信协议(http、ftp、tcp.........)

     

 

小结:

  1. 网络编程中两个主要的问题:

    • 如何准确的定位到网络上的一台或多台主机

    • 找到主机之后如何进行通信

  2. 网络编程中的要素:

    • ip地址和端口号

    • 网络通信协议

  3. 万物皆对象

 

IP

ip地址:InetAddress(IP地址是由IP使用的32位或128位无符号数字,构建UDP和TCP协议的低级协议。

  • 唯一定位一台网络上的计算机

  • 127.0.0.1 : 本机localhost

  • IP地址的分类

    • IPV4 / IPV6

      • IPV4:127.0.0.1 4个字节组成 0~255 2011年就用尽

      • IPV6 : 128位 8个无符号整数 fe80::98ea:c2a3:f308:2719%42 (加了模运算,应该是8位的)

    • 公网(外网、互联网) 私网(内网、局域网)

  • 域名:记忆IP问题

    IP:www.vip.com

 package com.network;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 
 //测试IP
 public class TestInetAddress {
     public static void main(String[] args) throws UnknownHostException {
         InetAddress localHost = InetAddress.getLocalHost();
         System.out.println(localHost);
 
         InetAddress byName = InetAddress.getByName("www.baidu.com");
         System.out.println(byName);
 
         System.out.println("----------------");
 
         System.out.println(byName.getHostAddress());  //获得ip
         System.out.println(byName.getHostName());     //获得域名
    }
 }
 /*
 DESKTOP-DQRDJG2/192.168.0.100
 www.baidu.com/220.181.38.150
 ----------------
 220.181.38.150
 www.baidu.com
  */
 

 

端口

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

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

  • 端口号的范围被规定为:0~65535(2的16次方-1)

  • 其中,TCP,NCP 都有 总的端口就有:65536*2 单个协议下,端口号不能冲突

  • 端口分类:

    • 公有端口: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 "138"   #查看指定的端口
       tasklist|findstr "40600"    #查看指定端口的进程
       Ctrl + shift + ESC   #快捷键 打开任务管理器

 

 package com.network;
 
 import java.net.InetSocketAddress;
 
 public class TestInetSocketAddress {
     public static void main(String[] args) {
         InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 8080);
         System.out.println(inetSocketAddress);
 
         System.out.println(inetSocketAddress.getAddress());
         System.out.println(inetSocketAddress.getHostName());
         System.out.println(inetSocketAddress.getPort());
    }
 }
 /*
 /127.0.0.1:8080
 /127.0.0.1
 127.0.0.1
 8080
  */
 

通信协议

协议:约定

网络通信协议:速率、传输码率、代码结构、传输控制......

问题非常复杂,解决的办法:分层(上面有,TCP/IP 4层概念模型)

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

其中重要的是:

  • TCP:用户传输协议

  • UDP:用户数据报协议

其中出名的协议:

  • TCP:

  • IP:网络互连协议

TCP UDP 的对比:

TCP:相当于打电话 有连接 且稳定

三次握手 四次挥手

 形象比喻:
 
 连接最少需要三次,保证稳定连接
 A:你愁啥?
 B:瞅你咋地
 A:干一架
 
 断开连接需要四次
 A:我要走了
 B:你真的要走了吗?
 B:你真的真的要走了吗?
 A:我真的要走了啊

客户端和服务端之间数据交互

传输完成,释放连接 效率低

 

UDP:相当于发短信 不连接 不稳定

有客户端 服务端:没有明确的界限,客户端可以和服务端交互,也可以客户端和客户端交互

不管有没有连接好 都可以直接发给你

TCP

tcp实现聊天:

客户端:Client

  1. 连接服务器 Socket

  2. 发送消息

 package com.network;
 
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.InetAddress;
 import java.net.Socket;
 import java.net.UnknownHostException;
 
 //客户端
 public class TestClient {
     public static void main(String[] args) {
 
         Socket socket =null;
         OutputStream os =null;
         try {
             // 1.确定所连服务端的ip和端口号
             InetAddress localHost = InetAddress.getLocalHost();
             int port=9999;
             // 2.创建一个socket连接
             socket = new Socket(localHost, port);
             // 3.发送消息
             os = socket.getOutputStream();
             os.write("你好啊".getBytes());
        } catch (Exception e) {
             e.printStackTrace();
        }finally {
             if (os!=null){
                 try {
                     os.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
             if (socket!=null){
                 try {
                     socket.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
        }
    }
 }
 

 

服务端:Server

  1. 建立服务的端口 ServerSocket

  2. 等待用户的连接 accept

  3. 接收用户的消息

 package com.network;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.ServerSocket;
 import java.net.Socket;
 
 //服务端
 public class TestServer {
     public static void main(String[] args) {
         ServerSocket serverSocket =null;
         Socket accept =null;
         InputStream is=null;
         ByteArrayOutputStream baos =null;
         try {
             // 1.得先有个地址
             serverSocket = new ServerSocket(9999);
             // 2.等待客户端连接进来
             accept = serverSocket.accept();
             // 3.读取客户端发送的消息
             is = accept.getInputStream();
 
             // 管道流 接受
             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 (accept!=null){
                 try {
                     accept.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
             if (serverSocket!=null){
                 try {
                     serverSocket.close();
                } catch (IOException e) {
                     e.printStackTrace();
                }
            }
        }
    }
 }
 

先运行TestServer 在运行TestClient 然后TestServer 就收到了

 

 

tcp实现文件上传:

服务器端:

 package com.network;
 
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.ServerSocket;
 import java.net.Socket;
 
 //服务端
 public class TestServer02 {
     public static void main(String[] args) throws Exception {
         //1. 有个地址 创建服务
         ServerSocket serverSocket = new ServerSocket(9955);
         //2. 等待客户端的连接
         Socket accept = serverSocket.accept();
         //3. 获取输入流
         InputStream is = accept.getInputStream();
 
         //4.文件接收输出 管道流
         FileOutputStream fos = new FileOutputStream("csdn01.png");
         byte[] bytes = new byte[1024];
         int len;
         while ((len=is.read(bytes))!=-1){
             fos.write(bytes,0,len);
        }
 
         //通知客户端 我接收完了
         OutputStream outputStream = accept.getOutputStream();
         outputStream.write("我接收完成".getBytes());
 
         //关闭资源
         outputStream.close();
         fos.close();
         is.close();
         accept.close();
         serverSocket.close();
    }
 }
 

客户端:

 package com.network;
 
 import java.io.ByteArrayOutputStream;
 import java.io.FileInputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.InetAddress;
 import java.net.Socket;
 
 //文件的上传
 //客户端发送给服务器
 public class TestClient02 {
     public static void main(String[] args) throws Exception {
         //1.确定所连服务端的ip和端口号
         InetAddress byName = InetAddress.getByName("192.168.0.100");
         int port = 9955;
         //2.创建一个连接
         Socket socket = new Socket(byName, port);
         //3.创建一个输出流
         OutputStream os = socket.getOutputStream();
 
         //4.读取本机文件
         FileInputStream fileIs = new FileInputStream("csdn.png");
         //5.写出文件
         byte[] buffer = new byte[1024];
         int len;
         while ((len=fileIs.read(buffer))!=-1){
             os.write(buffer,0,len);
        }
 
         //通知服务器 我传输完了
         socket.shutdownOutput();
 
         //确定服务器接收完毕,断开连接
         InputStream inputStream = socket.getInputStream();
         //String byte[]
         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
         byte[] bytes = new byte[1024];
         int len2;
         while ((len2=inputStream.read(bytes))!=-1){
             byteArrayOutputStream.write(bytes,0,len2);
        }
 
         System.out.println(byteArrayOutputStream.toString());
         
         //关闭资源
         byteArrayOutputStream.close();
         inputStream.close();
         fileIs.close();
         os.close();
         socket.close();
         
    }
 }
 

 

UDP

udp相当于发短信 只需要发送 不需要建立连接

public class DatagramSocket :此类表示用于发送和接受数据报包的套接字

数据报套接字是分组传送服务的发送或接收点。 在数据报套接字上发送或接收的每个数据包都被单独寻址和路由。 从一个机器发送到另一个机器的多个分组可以不同地路由,并且可以以任何顺序到达。

 

public final class DatagramPacket :此类表示数据报包

数据报包是用于实现无连接分组传送服务。仅基于该数据包中包含的信息,每个消息从一台机器路由到另一台机器。 从一台机器发送到另一台机器的多个分组可能会有不同的路由,并且可能以任何顺序到达。 包传送不能保证


udp发送信息

发送端:

 package com.network;
 
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.InetAddress;
 
 //发送端
 public class TestSend {
     public static void main(String[] args) throws Exception {
         //1.建立一个连接服务
         DatagramSocket datagramSocket = new DatagramSocket();
         //2.建包
         String msg="你好你好";
         //发送给谁
         InetAddress localHost = InetAddress.getLocalHost();
         int port=9898;
         //3.发送包
         DatagramPacket datagramPacket = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localHost, port);
         datagramSocket.send(datagramPacket);
 
         //关闭资源
         datagramSocket.close();
    }
 }
 

接收端:

 package com.network;
 
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 
 //接收端
 public class TestReceive {
     public static void main(String[] args) throws Exception {
         //1. 开放端口
         DatagramSocket datagramSocket = new DatagramSocket(9898);
         //接收数据包
         byte[] bytes = new byte[1024];
         DatagramPacket datagramPacket = new DatagramPacket(bytes, 0, bytes.length);
 
         datagramSocket.receive(datagramPacket);   //阻塞接受
 
         System.out.println(datagramPacket.getAddress().getHostAddress());
         System.out.println(new String(datagramPacket.getData(),0,datagramPacket.getLength()));
         //关闭连接
         datagramSocket.close();
    }
 }
 

最后输出结果:

 

udp实现聊天

初始代码:发送方循环发送 接收方可循环接受

发送方:

 package com.network.udp.chat;
 
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.InetSocketAddress;
 
 //发送方循环发送
 public class Send01 {
     public static void main(String[] args) throws Exception {
         DatagramSocket datagramSocket = new DatagramSocket();
         //准备数据 控制台读取System.in
         while (true){
             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
             String data=bufferedReader.readLine();
             if (data.equals("bye")){
                 break;
            }
             byte[] bytes = data.getBytes();
 
             DatagramPacket datagramPacket = new DatagramPacket(bytes,0 ,bytes.length ,new InetSocketAddress("localhost", 8866));
             datagramSocket.send(datagramPacket);
        }
         datagramSocket.close();
    }
 }
 

 

接收方:

 package com.network.udp.chat;
 
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 
 //接收方循环接收
 public class Receive01 {
     public static void main(String[] args) throws Exception {
         DatagramSocket datagramSocket = new DatagramSocket(8866);
         while (true){
             byte[] bytes = new byte[1024];
             DatagramPacket datagramPacket = new DatagramPacket(bytes, 0, bytes.length);
 
             datagramSocket.receive(datagramPacket);
 
             datagramPacket.getData();
 
             String s = new String(datagramPacket.getData(), 0, datagramPacket.getLength());
             System.out.println(s);
             if (s.equals("bye")){
                 break;
            }
        }
         datagramSocket.close();
    }
 }
 

最后可以实现 控制台循环输入输出

 

升级代码:通过多线程实现双方聊天

发送线程:

 package com.network.udp.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;
 
 public class TalkSend implements Runnable{
     DatagramSocket datagramSocket=null;
     BufferedReader bufferedReader =null;
 
     private String yourIP;
     private int yourPort;
 
     public TalkSend(String yourIP, int yourPort) {
         this.yourIP = yourIP;
         this.yourPort = yourPort;
 
         try {
             datagramSocket=new DatagramSocket();
             bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        } catch (Exception e) {
             e.printStackTrace();
        }
    }
 
     @Override
     public void run() {
         //准备数据 控制台读取System.in
         while (true){
             String data= null;
             try {
                 data = bufferedReader.readLine();
            } catch (IOException e) {
                 e.printStackTrace();
            }
             if (data.equals("bye")){
                 break;
            }
             byte[] bytes = data.getBytes();
 
             DatagramPacket datagramPacket = new DatagramPacket(bytes,0 ,bytes.length ,new InetSocketAddress(yourIP, yourPort));
             try {
                 datagramSocket.send(datagramPacket);
            } catch (IOException e) {
                 e.printStackTrace();
            }
        }
         datagramSocket.close();
    }
 }
 

接收线程:

 package com.network.udp.chat;
 
 import java.io.IOException;
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.SocketException;
 
 public class TalkReceive implements Runnable {
     DatagramSocket datagramSocket=null;
 
     private int port;
     private String name;
 
     public TalkReceive(int port, String name) {
         this.port = port;
         this.name = name;
 
         try {
             datagramSocket = new DatagramSocket(port);
        } catch (SocketException e) {
             e.printStackTrace();
        }
    }
 
     @Override
     public void run() {
 
         while (true){
             byte[] bytes = new byte[1024];
             DatagramPacket datagramPacket = new DatagramPacket(bytes, 0, bytes.length);
 
             try {
                 datagramSocket.receive(datagramPacket);
            } catch (IOException e) {
                 e.printStackTrace();
            }
 
             datagramPacket.getData();
 
             String s = new String(datagramPacket.getData(), 0, datagramPacket.getLength());
             System.out.println(name+" :"+s);
             if (s.equals("bye")){
                 break;
            }
        }
         datagramSocket.close();
    }
 }
 

学生端:

 package com.network.udp.chat;
 
 public class TalkStudent {
     public static void main(String[] args) {
         TalkSend send = new TalkSend("localhost", 8866);
         new Thread(send).start();
         TalkReceive receive = new TalkReceive(6688, "教师");
         new Thread(receive).start();
    }
 }
 

教师端:

 package com.network.udp.chat;
 
 public class TalkTeacher {
     public static void main(String[] args) {
         TalkSend send = new TalkSend("localhost", 6688);
         new Thread(send).start();
         TalkReceive receive = new TalkReceive(8866, "学生");
         new Thread(receive).start();
    }
 }
 

 

URL下载网络资源

https://www.baidu.com/

url:统一资源定位符,定位资源的,可以定位互联网上的某一个资源

 url的组成:5部分  可以少 不可以多
 
 协议://ip地址:端口号/项目名/资源

url:

 package com.network;
 
 import java.net.MalformedURLException;
 import java.net.URL;
 
 public class TestUrl01 {
     public static void main(String[] args) throws MalformedURLException {
         URL url = new URL("https://www.baidu.com/");
         System.out.println(url.getPort());  //端口号
         System.out.println(url.getHost());  //ip
         System.out.println(url.getPath());  //文件
         System.out.println(url.getFile());  //文件全路径
         System.out.println(url.getProtocol());  //协议
 
    }
 }
 /*
 -1
 www.baidu.com
 /
 /
 https
  */
 

url下载网络资源:

 package com.network;
 
 import javax.net.ssl.HttpsURLConnection;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.HttpURLConnection;
 import java.net.URL;
 
 
 public class TestUrl02 {
     public static void main(String[] args) throws IOException {
         //下载地址
         URL url = new URL("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png");
 
         //连接到这个资源 Https协议
         HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
 
         InputStream inputStream = urlConnection.getInputStream();
 
         FileOutputStream fileOutputStream = new FileOutputStream("baidu001.jpg");
 
         byte[] bytes = new byte[1024];
         int len;
         while ((len=inputStream.read(bytes))!=-1){
             fileOutputStream.write(bytes,0,len);  //写出这个数据
        }
         fileOutputStream.close();
         inputStream.close();
         urlConnection.disconnect();  //不连接了 也相当于close
 
    }
 }
 

 

 

posted @ 2022-04-06 18:56  超、自律即自由  阅读(14)  评论(0编辑  收藏  举报