Java核心类库(五)——网络编程

一、 网络常识

计算机网络

分布在不同地域的计算机, 通过硬件等网络设备使用通信线路互相连接形成的一个网格系统

作用:信息传递、资源共享

IP地址

IP地址是计算机在互联网中(公网IP)的唯一标识 ,就像人在社会中的身份证号码

IP地址分为IPv4和IPv6

内网IP(局域网IP):家庭内部的内部IP
公网IP:互联网中的IP

本机IP(localhost):127.0.0.1
(无论是否插网线,都能够查找到本机)

域名

域名可以简单的理解为IP地址的别名,让IP地址更好记

当输入域名后(例如www.baidu.com) , 计算机会访问域名解析商 , 然后得到IP地址, 再进行访问

打开百度,按F12或者Ctrl+Shift+I进入,点击Network,刷新页面查看Remote Address

在这里插入图片描述
复制IP地址,进行访问,可见该IP地址对应的就是百度的域名www.baidu.com

在这里插入图片描述

端口号

范围: 0 ~ 65535

IP地址是计算机在网络中的唯一标识,端口号是计算机中程序的标识 ,用于在一台计算机中区分不同的应用程序

端口号在使用时 , 应尽量避免0 ~ 1024(已知端口,已经被一些知名的软件 和 windows操作系统所占用)

通信协议

计算机与计算机之间交流的标准,是对数据传输速率、传入接口、步骤控制、出错控制等等制定的一套标准,双方必须同时遵守,最终完成数据的交换

常用的通信协议:

  1. http协议 : 超文本传输协议 . 80端口号
  2. https协议: 安全的超文本传输协议 443端口号
  3. ftp协议: 文件传输协议 21端口号
  4. TCP协议: 传输控制协议(面向连接、可靠)
  5. UDP协议: 用户数据报协议(面向无连接、不可靠)

TCP协议

传输控制协议

面向连接的、可靠的协议

面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接、再传输数据,提供了可靠无差错的数据传输

TCP协议客户端与服务器连接时,三次握手,确保消息能准确无误的发送

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

断开连接时,四次挥手释放

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

TCP三次握手四次挥手参考文章:两张动图-彻底明白TCP的三次握手与四次挥手

UDP协议

用户数据报协议

面向无连接的、不可靠的协议

OSI模型

指的是从一台计算机的软件中,将数据发送到另一台计算机的软件中的过程

七层网络模型:
应用层 / 表现层 / 会话层 / 传输层 / 网络层 / 数据链路层 / 物理层

编程程序的分类

  1. B/S 程序 : 浏览器与服务器程序
  2. C/S 程序 : 客户端与服务器程序(本章侧重)

二、 TCP协议的C/S程序

基于TCP的网络编程,即TCP协议的C/S程序

涉及知识点:

  1. ip地址
  2. 端口号
  3. 网络协议

用到的类

  1. ServerSocket 搭建服务器
  2. Socket 搭建客户端

先有服务器,客户端再连服务器

两方使用socket(套接字 , 通信端点) 进行交流


ServerSocket

用于创建服务器,创建完毕后,会绑定一个端口号,然后此服务器可以等待客户端连接

每连接一个客户端,服务器就会得到一个新的Socket对象,用于跟客户端进行通信

构造方法

创建一个基于TCP/IP协议的服务器 , 并绑定指定的端口号

注意 : 参数port的范围是: 0 ~ 65535 (建议1025 ~ 65535)

ServerSocket(int port); //port为端口号

Socketd的构造方法为Socket(String ip,int port) ,ip为ServerSocket的IP地址,port为ServerSocket的端口号

服务器创建以后,需要通过accept方法等待客户端连接,连接之后执行

运行结束,close关闭

常用方法

  • 等待客户端连接

    Socket accept();

    此方法会导致线程的阻塞,直到一个新的客户端连接成功并return Socket对象后, 线程再继续执行

  • 释放占用的端口号 , 关闭服务器

    void close();


Socket

是两台计算机之间通信的端点 , 是网络驱动提供给应用程序编程的一种接口 一套标准, 一种机制

构造方法

Socket(String ip,int port), ip为ServerSocket的IP地址,port为ServerSocket的端口号

创建一个套接字, 并连接指定ip和端口号的服务器

常用方法

  • OutputStream getOutputStream();
    返回指向通信的另一端点的输出流(发)
  • InputStream getInputStream();
    返回指向通信的另一端点的输入流(收)
  • void close();
    关闭套接字

其他方法

变量和类型方法描述
InetAddressgetInetAddress()返回套接字连接的地址
intgetPort()返回此套接字连接的远程端口号
booleanisClosed()返回套接字的关闭状态
booleanisConnected()返回套接字的连接状态

TCP协议网络编程

在网络编程时,获取输入输出流的操作,对于客户端与服务器来说是相对的

客户端的输入流, 输入的是服务器的输出流(输出的内容)
客户端的输出流,输出到了服务器的输入流中

所以在使用时需要注意:客户端与服务器获取流的顺序必须是相反的
(例如客户端先得到了输入流 , 则服务器必须先获取输出流)

简单实现

以本机与本机交流为例

tips:
发消息用输出流
收消息用输入流

服务器
  • 搭建一个服务器
        ServerSocket server = new ServerSocket(55565);
        System.out.println("服务器启动完毕!");
  • 等待客户端连接
        Socket socket = server.accept();
        System.out.println("一个客户端连接了");
  • 输出流,相当于客户端的输入流
		//获取输出流
        OutputStream os = socket.getOutputStream();
        //将字节输出流, 转换为打印流
        PrintStream ps = new PrintStream(os);
        //将服务器输入的内容发送给客户端
        ps.println("欢迎连接服务器!");
  • 输入流,收到的客户端的回话
		//获取输入流
        InputStream is = socket.getInputStream();
        //将输入的字节流 ,转换为字符流
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String text = br.readLine();
        //将文字打印给客户端
        System.out.println("服务器收到客户端的回复:" + text);
客户端
  • 连接到服务器
    连接指定ip(本机ip:127.0.0.1)和端口号(和服务器的端口号相同,即55565)
        Socket socket = new Socket("127.0.0.1",55565);
  • 输入流,即服务器输出的内容
		//得到输入流
        InputStream is = socket.getInputStream();
        //将字节输入流, 转换为字符输入流 , 并转换为逐行读取流
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String text = br.readLine();
        //将文字打印给服务器
        System.out.println("客户端接到消息:" + text);
  • 输出流,即服务器的输入流(服务器收到的回话)
		//得到输出流
        OutputStream os = socket.getOutputStream();
        //将输出流转换为打印流
        PrintStream ps = new PrintStream(os);
        //将客户端输入的内容发送给服务器
        ps.println("服务器你好!");

运行

有了服务器,客户端才能连接到服务器,因此先运行服务器,可以看到服务器运行界面输出:

服务器启动完毕!

等待服务器启动完毕后,再运行客户端,客户端收到服务器的消息,可以看到客户端运行界面输出:

客户端接到消息:欢迎连接服务器!

此时客户端与服务器连接成功,服务器运行界面显示:

一个客户端连接了

客户端收到服务器的消息后对服务器进行回话,服务器运行界面显示:

服务器收到客户端的回复:服务器你好!

本次简单实现主要是服务器和客户端之间一个发一个收(单线程),服务器与客户端之间的收发操作是交替进行


加入多线程

简单实现中,一个服务器只能与一个客户端进行交流,而服务器一定希望与多个客户端进行交流,因此在之前的服务器中加入多线程,实现多线程的服务器

交互过程中注意:
服务器先输入则客户端先输出
服务器先输出则客户端先输入

服务器
  • 搭建服务器
        ServerSocket server = new ServerSocket(55565);
        System.out.println("服务器启动完毕!");
  • 使用while循环,实现与多个客户端进行连接
        while(true){
            Socket socket = server.accept();
            System.out.println("一个客户端连接了");
        }
客户端
  • 连接到服务器
    连接指定ip(本机ip:127.0.0.1)和端口号(和服务器的端口号相同,即55565)
      Socket socket = new Socket("127.0.0.1",55565);
运行

先打开服务器,服务器开始运行,服务器界面输出如下:

服务器启动完毕!

运行一次客户端程序,客户端与服务端连接,服务端界面输出:

一个客户端连接了

当再一次运行客户端时,客户端与服务端连接,服务端界面输出:

一个客户端连接了

由上述可知,此时可以有多个客户端与服务器建立连接,每次建立连接服务器界面都会输出:一个客户端连接了,想要同时与多个客户端进行连接,可以在客户端连接之后单独开一个线程,在新开线程的run方法中操作socket与用户进行交流

            new Thread(){
                @Override
                public void run() {
                    try {
                        InputStream is = socket.getInputStream();
                        OutputStream os = socket.getOutputStream();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            };

实现循环交流

实现循环交流,即启动服务器和客户端之后 服务器与客户端之间之间交流类似于我们日常的窗口聊天

服务器
  • 搭建服务器
        ServerSocket server = new ServerSocket(55565);
        System.out.println("服务器启动完毕,等待客户端连接中...");
  • 等待客户端连接
		Socket socket = server.accept();
  • 获取输入流、输出流、输入信息流
		//接收消息
        //获取输入流
        InputStream is = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
                        
        //发消息
        //获取输出流PrintStream字节,PrintWriter字符
        OutputStream os = socket.getOutputStream();
        PrintStream ps = new PrintStream(os);

        //从键盘获取输入信息流
        BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
  • 与客户端进行交流
       //与客户端交流
       SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
       String receive,send;
       System.out.println("已与客户端建立连接!");
       receive = br.readLine();//客户端消息
       while(true){
       		//收消息
            System.out.println("[客户端]   " + format.format(new Date()) + '\n' + receive + '\n');

            //发消息
            send = input.readLine();
            ps.println(send);
            ps.flush();

           //继续聊(接收消息)
           receive = br.readLine();

           if(receive.equals("bye")){
           		System.out.println("[客户端]   " + format.format(new Date()) + '\n' + receive + '\n');
          		break;
           }


      }//end while 交流
      input.close();
      br.close();
      ps.close();
      socket.close();
      server.close();
客户端
  • 连接到服务器
        Socket socket = new Socket("127.0.0.1",55565);
  • 获取输入流、输出流、输入信息流
		//接收消息
        //获取输入流
        InputStream is = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
                        
        //发消息
        //获取输出流PrintStream字节,PrintWriter字符
        OutputStream os = socket.getOutputStream();
        PrintStream ps = new PrintStream(os);

        //从键盘获取输入信息流
        BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
  • 与服务器进行交流
       SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 
       String receive,send;
       System.out.println("已与服务器建立连接!开始聊天吧");
       send = input.readLine();
       while(true){
            //发消息
            ps.println(send);
            ps.flush();

            //接收服务器回复的消息
            receive = br.readLine();
            System.out.println("[服务器]   " + format.format(new Date()) + '\n' +receive + '\n');

            send = input.readLine();

            if(send.equals("bye")){
                ps.println(send);
                break;
            }
       }//end while 聊天结束
       input.close();
       ps.close();
       br.close();
       socket.close();
运行

先打开服务器,服务器开始运行,服务器界面输出如下:

服务器启动完毕!

运行客户端程序,客户端与服务端连接,服务器界面输出:

一个客户端连接了

与服务器连接成功,客户端界面输出:

已与服务器建立连接!开始聊天吧

客户端输入“哈喽~”,可以在服务器界面看到:

[客户端]   2021071912:08:21
哈喽~

服务器回复输入“你好”,可以在客户端界面看到:

[服务器]   2021071912:08:23
你好

客户端输入“嘿嘿”,可以在服务器界面看到:

[客户端]   2021071912:08:27
嘿嘿

服务器回复输入“嗯哼”,可以在客户端界面看到:

[服务器]   2021071912:08:30
嗯哼

客户端输入“bye”,可以在服务器界面看到如下输出,此时会话结束,程序执行结束:

[客户端]   2021071912:08:33
bye

三、 补充

InetAddress

描述IP地址的类,所创建的对象用于描述IP地址

在UDP协议中. 通过数据包DatagramPacket的getAddress方法, 可以得到数据包来自哪个IP
在TCP协议中, 通过套接字Socket的getInetAddress方法, 可以得到套接字连接的IP地址

  • 创建对象
InetAddress ip = InetAddress.getByName("192.168.102.228");
  • 常用方法
  1. String getHostAddress()
    获取IP地址字符串
  2. String getHostName()
    获取计算机名称,当名称无法获取时,获取的为ip地址.
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Selcouther

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值