java-web学习-java基础-网络编程(tcp和udp)附tcp实现通信

Nortonary      2022-06-05     194

关键词:

网络编程

“Java是Internet上的语言”,其从语言级别上提供了完备的对网络应用程序的支持,联网的具体底层细节被封装在Java提供的网络类库中,而向所有平台提供统一的网络编程环境。

计算机网络基础

网络编程的目的就是通过网络协议实现和其他计算机的数据交换和通讯,而这个目的带来两个主要问题:

  1. 如何定位复杂网络系统中的特定主机?
  2. 如何在定位后进行可靠高效的数据传输?

其中第一个问题是通过IP地址+端口解决,IP地址定位主机位置,端口号定位主机上的特定应用,两者组合得到套接字(Socket)。而第二个问题这通过网络通信协议解决,而我们事实上的国际网络通信协议标准是TCP/IP参考模型

IP与Port

IP -> InetAddress类

其唯一标识Internet上的一个通信实体,而任何一个实体能够通过唯一的回环地址(127.0.0.1)指向自身。我们通常能够接触到的比如www.baidu.com这种称为“域名”,其是Internet上主机的另一种标识方式,本机回环使用的域名是localhost。当使用域名进行连接时,需要由域名服务器(DNS)进行解析,将域名转换成目标IP地址才能建立连接,这是域名解析的过程。

IP地址共有两种分类方式:

  1. IPV4:由4个字节组成,已经被用尽,以点分十进制标识,比如123.165.0.1
  2. IPV6:由16个字节组成,分为8个无符号整数,每个整数用4位十六进制数表示,以冒号分开,比如ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff

InetAddress类也因此分为两个子类:Inet4Address和Inet6Address。该类没有公有构造方法,需要通过getByName()或getLocalHost()方法返回对应的实例。可以通过getHostName()或getHostAddress()获取相关信息。可以发现,Java把域名解析、连接DNS服务器等底层细节都封装地非常完全。

Port

端口是主机用于标识目前正在计算机上运行的应用,或者我们可以称为程序。为了规范,我们对端口有一套公认的分配标准:

  1. 0~1023:公认端口,已经被预定义的通信服务程序占据,它们与一些服务紧密绑定,通常是一些通信协议。
  2. 1024~49151:注册端口,可以被分配给用户进程或应用。
  3. 49152~65535:动态/私有端口,理论上,不应为服务分配这些端口。

网络通信协议

网络通信协议,我们耳熟能详,但是它究竟规定了些什么呢?网络通信协议覆盖的范围极广,比如压缩解压缩、如何控制流量、如何指定地址、如何进行加密,这也使得网络通信协议非常复杂。

TCP/IP采用了通信协议分层的思想,将一个复杂的通信协议分解为多个协议,并分层管理:上一层调用下一层而不能与再下面的一层发生关系,同层间可通信。

TCP/IP中的TCP(Transmission Control Protocol)和IP(Internet Protocol)只是TCP/IP协议簇中的两个,事实上,TCP/IP是一个极为庞大的多个协议组成的协议簇,从顶到底分为应用层、传输层、网络层、物理+数据链路层四层,其中TCP属于传输层,IP属于网络层,此外还有HTTP(属于应用层)、DNS(属于应用层)、Link(属于物理链路层)。

URL 定位

URL,Uniform Resource Locator,统一资源定位符。我们之前说,我们可以用IP地址+Port定位到Internet上任意一个主机上的应用,但是这其实还不够。我们不仅访问应用,还需要访问特定的资源,比如图片、视频等。同时,我们在链接到一个通信实体时并不知道他支持什么样的通信协议,贸然链接可能引起很多问题。

URL由五部分组成:

http://192.168.1.100:8080/helloworld/index.jsp#a?username=shkstart&password=123
  1. 传输协议:http
  2. 主机名:IP地址或域名
  3. 端口号:端口号
  4. 文件名:目标通信实体上的文件名称
  5. 片段名:某个资源片段名称,比如小说的某个章节号
  6. 参数列表:需要传递的参数名称,比如用户名等

Java下利用URL类来描述一个URL,并提供解析和构造方法。我们可以通过字符串来创建一个URL对象,并调用Java提供的方法来分析这个URL请求的究竟是什么资源。

Restful的风格

当我们使用URL访问同一个资源时,理论上不同的操作对应不同的参数列表(至多再对应不同的片段名),即我们使用参数列表进行传参,从而告诉服务端我们需要进行什么操作。

而Restful的风格鼓励我们使用请求地址传参,即将参数放在路径名中成为路径的一部分,而省去参数列表:

https://mygraph.cn/addTwoInt?a=100&b=1000  传统
https://mygraph.cn/addTwoInt/100/1000    restful风格

好处在于路径更加整洁;同时由于框架会自动进行类型转换,获取参数更加方便;以及参数异常时不再是方法内参数转化失败, 而是指示路径和方法不匹配。

TCP网络编程

TCP网络编程基础是Socket,即套接字。

Socket 套接字

Socket将网络连接视作一个流,数据在两个Socket间通过IO传输,分为两类:

  • 流套接字:TCP下提供字节流服务
  • 数据报套接字:UDP下的数据报服务

Java下的基于Socket的TCP编程

Java下TCP网络编程分为服务端编程客户端编程

客户端需要:

  1. 创建根据目标服务端建立通信套接字Socket对象,若对方未响应者报异常。
  2. 获取链接到目标Socket的输入输出流,这是基于Java的流传输相关的标准库的。
  3. 按照一定协议对Socket进行读/写:通过输入流读取服务器传来的信息,通过输出流将信息写进传输流。
  4. 关闭通信套接字Socket

服务端需要:

  1. 调用ServerSocket创建一个属于服务端的套接字对象,用于监听客户端
  2. 调用accept()方法,一旦接受连接,该方法返回一个通信套接字对象
  3. 获取该通信套接字的输入输出流
  4. 关闭ServerSocket和通信套接字(注意到这两个而是不一样的)

UDP网络编程

UDP是另一种传输层的网络通信协议,不同于TCP的流传输,其采用类似于消息的数据报方式传递信息。其将发送方和接收方的IP+port放到了数据报中

两个通信实体间通过互相发送数据报的方式传递信息,就像发送快递包裹一样。这带来很高的不可靠性,任何一方都不会关心对方是否正确接收数据。

但是这也使得双方能够在不建立连接的情况下进行通信,极大地减少了通信延迟,这使得当实时性需求很高时,UDP通信比TCP更加常见。同时这种“不负责任”的乱丢数据,也支持一对多的广播机制

Java下的UDP编程

Java使用DatagramSocket类表示套接字,DatagramPacket类表示数据报。

发送方:

  1. 建立一个套接字对象socket代表发送方实体
  2. 建立一个数据报对象packet,并将接收方的IP地址+Port放到里面
  3. 调用套接字对象socket.send(packet)发送数据报

接收方:

  1. 建立一个套接字对象socket代表当前接收方
  2. 建立一个缓冲区byte[]并将它传入一个数据报对象从而进行关联
  3. 调用socket.receive(packet),进入等待接收状态
  4. 收到数据后,数据存储在与数据报对象关联的缓冲区里,通过调用packet.get*()来获得数据报对象内的所有信息。

实践代码(TCP实现)

// Server.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    ServerSocket server;

    public Server(){
        try{
            this.server = new ServerSocket(8888);
        } catch (Exception e){
            e.printStackTrace();
        }

    }
    public void serve(){
        System.out.println("Qiume is online!");
        while (true){
            try{
                Socket communication = this.server.accept();
                OutputStream out = communication.getOutputStream();

                synchronized (out){
                    out.write("Hello, who are U?".getBytes());
                }

                InputStream in = communication.getInputStream();
                StringBuilder receivedMsg = new StringBuilder();
                synchronized (in){
                    int c;
                    for (c = in.read(); in.available()!=0; c = in.read()) {
                        receivedMsg.append((char) c);
                    }
                    receivedMsg.append((char) c);
                }
                System.out.println("Qiume received:" + receivedMsg.toString());

                synchronized (out){
                    out.write("I love you, too".getBytes());
                }

                communication.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

// Client.java
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Client {
    Socket communication;

    public Client() {

    }

    public void start() {
        System.out.println("Norton visits!");
        try {
            try {
                this.communication = new Socket("localhost", 8888);
            } catch (Exception e) {
                e.printStackTrace();
            }
            InputStream in = communication.getInputStream();
            StringBuilder receivedMsg = new StringBuilder();

            synchronized (in) {
                int c;
                for (c = in.read(); in.available() != 0; c = in.read()) {
                    receivedMsg.append((char) c);
                }
                receivedMsg.append((char) c);
            }


            System.out.println("Norton received:" + receivedMsg.toString());

            OutputStream out = communication.getOutputStream();

            synchronized (out) {
                out.write("Hello Qiume, this is Norton, I love you!".getBytes());
            }

            synchronized (in) {
                receivedMsg = new StringBuilder();
                int c;
                for (c = in.read(); in.available() != 0; c = in.read()) {
                    receivedMsg.append((char) c);
                }
                receivedMsg.append((char) c);
            }

            System.out.println("Norton received:" + receivedMsg.toString());

            communication.close();
            System.out.println("Norton out!");
        } catch (Exception e) {
            e.printStackTrace();
        }


    }
}

//Main.java
public class Main {
    public static void main(String[] args) throws InterruptedException {
        Runnable client = new Runnable() {
            @Override
            public void run() {
                Client norton = new Client();
                norton.start();
            }
        };
        Runnable server = new Runnable() {
            @Override
            public void run() {
                Server qiume = new Server();
                qiume.serve();
            }
        };
        new Thread(server).start();
        while (true){
            Thread.sleep(1000);
            new Thread(client).start();
        }
    }
}

java-web学习-java基础-java8新特性(局部)

Java8新特性我在本篇中仅介绍作为初学者所需要知道的Java8的新特性,而对新的编译工具、引擎等作忽略处理,此外还有些功能上新特性没写进来。目录Java8新特性默认方法Lambda表达式流操作StreamAPI与批处理新的DatetimeAPIOptional类... 查看详情

java基础学习网络编程简介

基础知识:1、osi分层模型和TCP/IP分层模型对应关系 2、七层模型与协议的对应关系网络层------------IP(网络之间的互联协议)传输层------------TCP(传输控制协议)、UDP(用户数据报协议)应用层------------Telnet(Internet远程登录... 查看详情

java网络爬虫基础学习

 刚开始接触java爬虫,在这里是搜索网上做一些理论知识的总结  主要参考文章:gitchat的java网络爬虫基础入门,好像要付费,也不贵,感觉内容对新手很友好。  一、爬虫介绍  网络爬虫是一个自动提取网页的程序,它... 查看详情

如何夯实(java)编程基础,并深入学习和提高

如何夯实(Java)编程基础,并深入学习和提高?240赞同反对,不会显示你的姓名匿名用户240 人赞同多学习。。。网上自学的学习网站很多,见以下榜单~一、汇总榜单:公开课_学习网站导航收录了网易、多贝、传课等众多公... 查看详情

java学习路线图

...)    3. 高级编程(集合、异常、IO、多线程、网络编程、反射、泛型、序列化、Java8&Java9)  学习渠道:    慕课 查看详情

学习易语言,tc,按键精灵,这三个软件如何选择,说明各有啥好处

按键精灵,tc简单开发,易语言哪个更好?按键精灵,学习容易。TC简单开发,学习要难一些。一、是因为TC采用C语言,C++系列语法。采用C语言,C++系列框架。二、TC起步迟一些,TC的教程少,用户少,讨论的问题少,百度找到的... 查看详情

java菜鸟学习总结java基础知识(类)(代码片段)

目录【Java菜鸟学习总结】Java基础知识(类)1、面向对象编程2、类3、static关键字4、final关键字【Java菜鸟学习总结】Java基础知识(类)1、面向对象编程1.1、面向对象编程的特征面向对象编程(OOP)的三大特征封装;继承;多态;1.2、... 查看详情

java网络爬虫基础学习

尝试直接请求URL获取资源豆瓣电影https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=time&page_limit=20&page_start=0浏览器打开该地址:发现是这样的在这里我们需要用java抓取电影的信息,首先要找到资源链接,浏览... 查看详情

java网络爬虫基础学习

jsoup的使用jsoup介绍  jsoup是一款Java的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,css以及类似于Jquery的操作方法来取出和操作数据。主要功能从一个URL,文件或字符串中解析出HTML... 查看详情

java网络编程学习基础篇(代码片段)

一、基础背景时代背景自2000年左右,Web的快速发展以及2010左右的云原生和云计算的提出,网络通信的重要性越来越凸显出来;对于用户来说:软件的响应速度和体验是越来越重要的,而网络通信是决定响应速... 查看详情

java-web中生成文档

基于Java的解决方案也是很多的,包括使用Jacob、ApachePOI、Java2Word、iText等各种方式,其实在从Office2003开始,就可以将Office文档转换成XML文件,这样只要将需要填入的内容放上${}占位符,就可以使用像Freemarker这样的模板引擎将出... 查看详情

java-web开发环境和搭建

 JAVAWeb开发环境与搭建一、下载安装JDK1.配置jdk开发环境JAVA_HOME 2.path  二、下载安装eclipsejavaEE版本 三、安装部署tomcat3.1、安装:直接解压到指定目录即可。(注:目录不要太深;目录不要有中文或空格)3.2、... 查看详情

java编程语言基础知识点讲解

不管是对于JAVA编程的学习还是其他的编程语言,都是从零基础学起,那么就需要将所有零散的知识点整合在一起,这样系统地学习一门语言,才能更好的入门并且掌握,通过对基础知识点的学习与了解,才能更加深入的学习后... 查看详情

scala学习笔记编程基础

强烈推荐参考该课程:http://www.runoob.com/scala/scala-tutorial.html1.  Scala概述1.1. 什么是ScalaScala是一种多范式的编程语言,其设计的初衷是要集成面向对象编程和函数式编程的各种特性。Scala运行于Java平台(Java虚拟机),并... 查看详情

java并发编程系列之一并发理论基础

...一并发理论基础本系列文章开始Java并发编程的进阶篇的学习,为了初学者对多线程的初步使用有基本概念和掌握,前置知识会对一些基础篇的内容进行介绍,以使初学者能够丝滑入戏。多线程学习,真正的难点不在于多线程程... 查看详情

想学编程有空自己做脚本,学那个软件的好呢?易语言?按键精灵?还有其他吗?那个比较好呢?

学习方便性和发展方向好像是按键精灵比较适合啊,主要做游戏脚本按键精灵学起来容易些,尤其是后台操作比易语言要容易做,不过按键精灵游戏脚本的公开源码比较少,不易学习别人的代码,而且交流学习按键精灵脚本的论... 查看详情

零基础转行学习java编程,有哪些学习方法可以借鉴

中国互联网的加速发展,大概从1997年开始,前期是PC互联网,后来移动互联网,现在互联网+,再接下来物联网、智慧城市、智慧交通、人工智能,一路蓬勃发展,虽有小波折,大趋势从未变过,未来一面泛化、一面深化,十年... 查看详情

java网络爬虫基础学习

正则表达式正则表达式写法含义d代表0-9的任意数字D代表任何非数字字符s代表空格类字符S代表非空格类字符p{Lower}代表小写字母[a-z]p{Upper}代表大写字母[A-Z]p{Alpha}代表字母p{Blank}代表空格或制表符HTTP状态码分类描述1**信息,服务... 查看详情