精华内容
下载资源
问答
  • java网络编程

    2019-03-11 09:23:05
    java网络编程包括socket tcp/udp io/nio讲解 http协议 jdbc rmi java的安全框架等知识
  • Java网络编程》,附带《Java网络编程实例》和阅读器,欢迎下载
  • java网络编程pdf

    2017-11-14 10:05:27
    java网络编程pdf java网络编程pdf java网络编程pdf java网络编程pdf java网络编程pdf java网络编程pdf java网络编程pdf java网络编程pdf
  • java网络编程第四版pdf

    2018-06-07 10:19:54
    java网络编程第四版PDF,带目录和书签。 第一章 基本网络概念 第二章 流 第三章 线程 ...
  • java网络编程考试题库

    2018-11-27 12:50:10
    java网络编程考试题目,内含有Java网络编程期末复习题(I/O、多线程、网络编程、数据库操作),有答案
  • java网络编程常见面试题,包含,多线程,路由器,网络编程
  • Java网络编程(第4版)PDF

    2018-07-23 11:46:03
    Java网络编程(第4版)的电子版书籍,学习java通讯技术的同学建议看一下这本书
  • Java网络编程(第三版)高清PDF,可选文字版本,学习网络编程必看之书!!!
  • java网络编程精解_完整版 PDF电子书下载 带书签目录 java网络编程精解_完整版 PDF电子书下载 带书签目录
  • Java 网络编程

    万次阅读 多人点赞 2019-05-30 23:07:18
    网络编程 一、网络编程基础概念 首先理清一个概念:网络编程不等于网站编程,网络编程即使用套接字来达到进程间通信,现在一般称为TCP/IP编程。 计算机网络: 把分布在不同地理区域的计算机与专门的外部设备用通信...

    首先理清一个概念:网络编程不等于网站编程,网络编程即使用套接字来达到进程间通信,现在一般称为TCP/IP编程。

    一、计算机网络

    (一)概念

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

    (二)计算机网络的主要功能

    1. 资源共享
      资源共享包括计算机硬件资源、软件资源和数据资源的共享。硬件资源的共享提高了计算机硬件资源的利用率,由于受经济和其他因素的制约,这些硬件资派不可能所有用户都有,所以使用计算机网络不仅可以使用自身的硬件资源,也可共享网络上的资源。软件资源和数据资源的共享可以充分利用已有的信息资派.减少软件开发过程中的劳动,避免大型数据库的重复建设。
    2. 信息交换
      这是计算机网络最基本的功能.计算机网络中的计算机之间或计算机与终端之间,可以快速可靠地相互传递数据、程序或文件。例如,用户可以在网上传送电子邮件、交换数据,可以实现在商业部门或公司之间进行订单、发票等商业文件安全准确地交换。
    3. 均衡负荷与分布处理
      对于大型的任务或课题.如果都集中在一台计算机上.负荷太重,这时可以将任务分散到不同的计算机分别完成,或由网络中比较空闲的计算机分担负荷,各个计算机连成网络有利于共同协作进行重大科研课题的开发和研究。利用网络技术还可以将许多小型机或傲型机连成具有高性能的分布式计算机系统,使它具有解决复杂问题的能力,从而大大降低费用。
    4. 综合信息服务
      计算机网络可以向全社会提供各处经济信息、科研情报、商业信息和咨询服务,如Internet中的www就是如此。

    (三)计算机网络分类

    计算机网络按其覆盖的地理范围可分为如下3类:

    • 局域网(LAN)。局域网是一种在小区域内使用的,由多台计算机组成的网络,覆盖范围通常局限在10 千米范围之内,属于一个单位或部门组建的小范围网。
    • 城域网(MAN)。城域网是作用范围在广域网与局域网之间的网络,其网络覆盖范围通常可以延伸到整个城市,借助通信光纤将多个局域网联通公用城市网络形成大型网络,使得不仅局域网内的资源可以共享,局域网之间的资源也可以共享。
    • 广域网(WAN) 广城网是一种远程网,涉及长距离的通信,覆盖范围可以是个国家或多个国家,甚至整个世界。由于广域网地理上的距离可以超过几千千米,所以信息衰减非常严重,这种网络一般要租用专线,通过接口信息处理协议和线路连接起来,构成网状结构,解决寻径问题。

    二、网络通信协议及接口

    (一)网络通信协议

    计算机网络中实现通信必须有一些约定,即通信协议;包括对速率,传输代码,代码结构,传输控制步骤,出错控制等制定的标准。常见的网络通信协议有:TCP/IP协议、IPX/SPX协议、NetBEUI协议等。

    TCP/IP协议:传输控制协议/因特网互联协议(Transmission Control Protocol/Internet Protocal),是Internet最基本、最广泛的协议。它定义了计算机如何连入因特网,以及数据如何在它们之间传输的标准。它的内部包含一系列的用于处理数据通信的协议,并采用了4层的分层模型,每一层都呼叫它的下一层所提供的协议来完成自己的需求。

    (二)网络通信接口

    为了使两个节点之间能进行对话,必须在他们之间建立通信工具(即接口),使彼此之间,能进行信息交换。接口包括两部分:

    • 硬件装置:实现结点之间的信息传送
    • 软件装置:规定双方进行通信的约定协议

    (三)通信协议分层思想

    1.为什么要分层

    由于结点之间联系很复杂,在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常用的复合方式就是层次方式,及同层间可以通信,上一层可以调用下一层,而与再下一层不发生关系。各层互不影响,利于系统的开发和扩展。

    2.通信协议的分层规定

    把用户应用程序作为最高层,把物理通信线路作为最底层,将其间的协议处理分为若干层,规定每层处理的任务,也规定每层的接口标准。

    3.参考模型

    在这里插入图片描述
    上图中,TCP/IP协议中的四层分别是应用层、传输层、网络层和链路层,每层分别负责不同的通信功能。

    • 应用层:主要负责应用程序的协议,例如HTTP协议、FTP协议等。
    • 传输层:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。
    • 网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。
    • 数据链路层:链路层是用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动。

    我们编写的程序位于应用层,因此我们的程序是和TCP/UDP打交道的。

    (四)协议分类

    通信的协议还是比较复杂的,java.net包中包含的类和接口,它们提供低层次的通信细节,我们可以直接使用这些类和接口,来专注于网络程序开发,而不用考虑通信的细节。

    java.net包中提供了两种常见的网络协议的支持:TCP和UDP

    • TCP是可靠的连接,TCP就像打电话,需要先打通对方电话,等待对方有回应后才会跟对方继续说话,也就是一定要确认可以发信息以后才会把信息发出去。TCP上传任何东西都是可靠的,只要两台机器上建立起了连接,在本机上发送的数据就一定能传到对方的机器上。
    • UDP就好比发电报,发出去就完事了,对方有没有接收到它都不管,所以UDP是不可靠的。
    • TCP传送数据虽然可靠,但传送得比较慢;UDP传送数据不可靠,但是传送得快。

    1.UDP

    • 用户数据报协议(User Datagram Protocol)。
    • 数据报(Datagram):网络传输的基本单位
    • UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
    • 由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。
    • 但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时,不建议使用UDP协议。
    • 特点:数据被限制在64kb以内,超出这个范围就不能发送了。

    2.TCP

    • 传输控制协议(Transmission Control Protocol)。
    • TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。
    • 在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”。

    (1)三次握手

    TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。

    在这里插入图片描述

    • 第一次握手,客户端发送SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态。
      (客户端向服务器端发出连接请求,等待服务器确认。)
    • 第二次握手,服务器端收到SYN报文,回应一个SYN (SEQ=y)ACK(ACK=x+1)报文,进入SYN_RECV状态。(服务器端向客户端回送一个响应,通知客户端收到了连接请求。)
    • 第三次握手,客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状态。(客户端再次向服务器端发送确认信息,确认连接。)

    三次握手完成,TCP客户端和服务器端成功地建立连接,可以开始传输数据了。

    (2)四次挥手

    其次,TCP的客户端和服务端断开连接,需要四次挥手
    在这里插入图片描述

    • 客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文,之后客户端进入 FIN_WAIT_1 状态。
    • 服务端收到该报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSED_WAIT 状态。
    • 客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。
    • 等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。
    • 客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文,之后进入 TIME_WAIT 状态
    • 服务器收到了 ACK 应答报文后,就进入了 CLOSE 状态,至此服务端已经完成连接的关闭。
    • 客户端在经过 2MSL 一段时间后,自动进入 CLOSE 状态,至此客户端也完成连接的关闭。

    你可以看到,每个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手。这里一点需要注意是:主动关闭连接的,才有 TIME_WAIT 状态。

    为什么挥手需要四次?
    关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。服务器收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。从上面过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,从而比三次握手导致多了一次。参考

    通俗理解:

    • 三次握手
      A:我要过来了!B:我知道你要过来了!A:我现在过来!
    • 四次挥手
      A:我们分手吧!B:真的分手吗?B:真的真的要分手吗?A:是的!

    由此,可以可靠地进行连接和断开。

    三、IP协议

    (一)概念

    IP协议:网络互连协议

    在这里插入图片描述
    每个人的电脑都有一个独一无二的IP地址,这样互相通信时就不会传错信息了。

    (二)分类

    IP地址根据版本可以分类为:IPv4和IPv6

    IPv4IPv6
    地址长度IPv4协议具有32位(4字节)地址长度IPv6协议具有128位(16字节)地址长度
    格式IPv4 地址的文本格式为 nnn.nnn.nnn.nnn,其中 0<=nnn<=255,而每个 n 都是十进制数。可省略前导零。IPv6 地址的文本格式为 xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx,其中每个 x 都是十六进制数可省略前导零。
    数量共有43亿,30亿在北美,4亿在亚洲,2011年就已经用尽多到每一粒沙子都可以分配一个IPv6地址

    在这里插入图片描述
    IPv4又可以分为五类:

    • A类:在IP地址的四段号码中,第一段号码为网络号码,剩下的三段号码为本地计算机的号码;A类IP地址中网络的标识长度为8位,主机标识的长度为24位,A类网络地址数量较少,有126个网络,每个网络可以容纳主机数达1600多万(256的三次方-2)台。

    • B类:在IP地址的四段号码中,前两段号码为网络号码。B类IP地址中网络的标识长度为16位,主机标识的长度为16位,B类网络地址适用于中等规模的网络,有16384个网络,每个网络所能容纳的计算机数为6万多(256的二次方-2)台

    • C类:在IP地址的四段号码中,前三段号码为网络号码,剩下的一段号码为本地计算机的号码;此类地址中网络的标识长度为24位,主机标识的长度为8位,C类网络地址数量较多,有209万余个网络。适用于小规模的局域网络,每个网络最多只能包含254(256-2)台计算机

    • D类:此类IP地址在历史上被叫做多播地址(multicast address),即组播地址;在以太网中,多播地址命名了一组应该在这个网络中应用接收到一个分组的站点;多播地址的最高位必须是“1110”,范围从224.0.0.0到239.255.255.255

    • E类: 此类地址也不分网络地址和主机地址,它的第1个字节的前五位固定为“11110”,为将来使用保留,地址范围从240.0.0.1到255.255.255.254

    (三)InetAddress类

    说到IP地址,就要引入一个类:InetAddress
    此类表示互联网协议 (IP) 地址
    在这里插入图片描述

    InetAddress类无构造方法

    1.常用方法摘要

    byte[] getAddress()
    返回此 InetAddress 对象的原始 IP 地址。
    static InetAddress getByName(String host)
    在给定主机名的情况下确定主机的 IP 地址。
    String getHostAddress()
    返回 IP 地址字符串(以文本表现形式)。
    String getHostName()
    获取此 IP 地址的主机名。
    static InetAddress getLocalHost()
    返回本地主机。
    127.0.0.1:本机地址,主要用于测试。别名:Localhost

    案例演示1

    import java.net.InetAddress;
    import java.net.UnknownHostException;
    
    public class TestIP {
        public static void main(String[] args) throws UnknownHostException {
            //InetAdress类表示IP地址
    
            //获取本机IP
            InetAddress ip = InetAddress.getLocalHost();// ADMINISTRATOR/192.xxx.xxx.xxx
            System.out.println(ip);
            //获得主机名
            System.out.println(ip.getHostName());// ADMINISTRATOR
            //获得IP地址
            System.out.println(ip.getHostAddress());// 192.xxx.xxx.xxx
            //getLocalHost=getHostName+getHostAddress
            System.out.println(InetAddress.getByName("localhost"));
        }
    }
    

    案例演示2

    import java.net.InetAddress;
    import java.net.UnknownHostException;
    
    public class TestIP2 {
        public static void main(String[] args) throws UnknownHostException {
            InetAddress inetAddress = InetAddress.getByName("www.baidu.com");
            // 获取此 IP 地址的主机名。
            System.out.println(inetAddress.getHostName());
            //返回 IP 地址字符串(以文本表现形式)。
            System.out.println(inetAddress.getHostAddress());
        }
    }
    

    在这里插入图片描述

    四、端口

    • IP地址用来标识一台计算机,但是一台计算机上可能提供多种网络应用程序,如何来区分这些不同的程序呢?这就要用到端口。端口号是用来区分一台机器上不同的应用程序的。
    • 我们使用IP地址加端口号,就可以保证数据准确无误地发送到对方计算机的指定软件上了。
    • 端口是虚拟的概念,是一个逻辑端口。
    • 当我们使用网络软件一打开,那么操作系统就会为网络软件分配一个随机的端口号,或者打开的时候向系统要指定的端口号。
    • 通过端口,可以在一个主机上运行多个网络应用程序。端口的表示是一个16位的二进制整数,2个字节,对应十进制的0~65535
    • 端口号在计算机内部是占2个字节。一台机器上最多有65536个端口号。一个应用程序可以占用多个端口号。端口号如果被一个应用程序占用了,那么其他的应用程序就无法再使用这个端口号了。
    • 记住一点,我们编写的程序要占用端口号的话占用1024以上的端口号,1024以下的端口号不要去占用,因为系统有可能会随时征用。端口号本身又分为TCP端口和UDP端口,TCP的8888端口和UDP的8888端口是完全不同的两个端口。TCP端口和UDP端口都有65536个

    (一)分类

    1. 公有端口:0~1023
      • HTTP:80
      • HTTPS:443
      • FTP:21
      • Telnet:23
    2. 程序注册端口(分配给用户或者程序):1024~49151
      • Tomcat:8080
      • MySQL:3306
      • Oracle:1521
    3. 动态、私有端口:49152~65535

    (二)DOS命令查看端口

    • 查看所有端口:netstat -ano
    • 查看指定端口:netstat -ano|findstr "端口号"
    • 查看指定端口的进程:tasklist|findstr "端口号"

    (三)InetSocketAddress类

    说到端口,则要引入一个类:InetSocketAddress

    此类实现 IP 套接字地址(IP 地址 + 端口号)。

    1.构造方法摘要

    InetSocketAddress(InetAddress addr, int port)
    根据 IP 地址和端口号创建套接字地址。
    InetSocketAddress(int port)
    创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值。
    InetSocketAddress(String hostname, int port)
    根据主机名和端口号创建套接字地址。

    2.常用方法摘要

    InetAddress getAddress()
    获取 InetAddress。
    String getHostName()
    获取 hostname。
    int getPort()
    获取端口号。

    案例演示

    import java.net.InetAddress;
    import java.net.InetSocketAddress;
    
    public class TestPort {
        public static void main(String[] args) {
            InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1",8082);
            System.out.println(inetSocketAddress);
            //返回主机名
            System.out.println(inetSocketAddress.getHostName());
            //获得InetSocketAddress的端口
            System.out.println(inetSocketAddress.getPort());
            //返回一个InetAddress对象(IP对象)
            InetAddress address = inetSocketAddress.getAddress();
            System.out.println(address);
        }
    }
    

    在这里插入图片描述

    五、TCP网络编程和UDP网络编程

    网络编程也叫做Socket编程,即套接字编程。套接字指的是两台设备之间通讯的端点。

    在这里插入图片描述

    (一)TCP网络编程

    1.概述

    TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server)。

    (1)两端通信时步骤:

    1. 服务端程序,需要事先启动,等待客户端的连接。
    2. 客户端主动连接服务器端,连接成功才能通信。服务端不可以主动连接客户端。

    (2)在Java中,提供了两个类用于实现TCP通信程序:

    1. 客户端:java.net.Socket 类表示。创建Socket对象,向服务端发出连接请求,服务端响应请求,两者建立连接开始通信。
    2. 服务端:java.net.ServerSocket 类表示。创建ServerSocket对象,相当于开启一个服务,并等待客户端的连接。

    2.Socket类

    Socket 类:该类实现客户端套接字,套接字指的是两台设备之间通讯的端点。

    (1)构造方法摘要

    • public Socket(String host, int port) :创建套接字对象并将其连接到指定主机上的指定端口号。如果指定的host是null ,则相当于指定地址为回送地址
      回送地址(127.x.x.x) 是本机回送地址(Loopback Address),主要用于网络软件测试以及本地机进程间通信,无论什么程序,一旦使用回送地址发送数据,立即返回,不进行任何网络传输。

    案例演示

    Socket client = new Socket("127.0.0.1", 6666);
    

    (2)常用方法摘要

    • public InputStream getInputStream() : 返回此套接字的输入流。

      • 如果此Scoket具有相关联的通道,则生成的InputStream 的所有操作也关联该通道。
      • 关闭生成的InputStream也将关闭相关的Socket。
    • public OutputStream getOutputStream() : 返回此套接字的输出流。

      • 如果此Socket具有相关联的通道,则生成的OutputStream 的所有操作也关联该通道。
      • 关闭生成的OutputStream也将关闭相关的Socket。
    • public void close() :关闭此套接字。

      • 一旦一个socket被关闭,它不可再使用。
      • 关闭此socket也将关闭相关的InputStream和OutputStream 。
    • public void shutdownOutput() : 禁用此套接字的输出流。

      • 任何先前写出的数据将被发送,随后终止输出流。

    3.ServerSocket类

    ServerSocket类:这个类实现了服务器套接字,该对象等待通过网络的请求。

    (1)构造方法摘要

    • public ServerSocket(int port) :使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上,参数port就是端口号。

    案例演示

    ServerSocket server = new ServerSocket(6666);
    

    (2)常用方法摘要

    • public Socket accept() :侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信。该方法会一直阻塞直到建立连接。

    4.代码实现

    案例演示1

    客户端:

    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.InetAddress;
    import java.net.Socket;
    
    public class TCPClient {
        public static void main(String[] args){
            Socket socket = null;
            OutputStream os = null;
            try {
                //1、创建Socket对象,它的第一个参数需要的是服务端的IP,第二个参数是服务端的端口
                InetAddress inet = InetAddress.getByName("127.0.0.1");
                socket = new Socket(inet,8090);
                //2、获取一个输出流,用于写出要发送的数据
                os = socket.getOutputStream();
                //3、写出数据
                os.write("你好,我是客户端!".getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {//4、释放资源
                if(socket!=null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(os!=null){
                    try {
                        os.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    服务端:

    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class TCPServer {
        public static void main(String[] args) {
            ServerSocket serverSocket = null;
            Socket socket = null;
            InputStream is = null;
            ByteArrayOutputStream baos = null;
            try {
                //1、创建服务端的ServerSocket,指明自己的端口号
                serverSocket = new ServerSocket(8090);
                //2、调用accept接收到来自于客户端的socket
                socket = serverSocket.accept();//阻塞式监听,会一直等待客户端的接入
                //3、获取socket的输入流
                is = socket.getInputStream();
    
    //        不建议这样写:因为如果我们发送的数据有汉字,用String的方式输出可能会截取汉字,产生乱码
    //        int len=0;
    //        byte[] buffer = new byte[1024];
    //        while ((len=is.read(buffer))!=-1){
    //            String str = new String(buffer, 0, len);
    //            System.out.println(str);
    //        }
                
                //4、读取输入流中的数据
                //ByteArrayOutputStream的好处是它可以根据数据的大小自动扩充
                baos = new ByteArrayOutputStream();
                int len=0;
                byte[] buffer = new byte[1024];
                while ((len=is.read(buffer))!=-1){
                    baos.write(buffer,0,len);
                }
                System.out.println("收到了来自于客户端"+socket.getInetAddress().getHostName()
                        +"的消息:"+baos.toString());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {//5、关闭资源
                if(serverSocket!=null){
                    try {
                        serverSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(socket!=null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(is!=null){
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(baos!=null){
                    try {
                        baos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    

    在这里插入图片描述
    服务器是没有IO流的,服务器可以获取到请求的客户端对象socket
    使用每个客户端socket中提供的IO流和客户端进行交互
    服务器使用客户端的字节输入流读取客户端发送的数据
    服务器使用客户端的字节输出流给客户端回写数据

    案例演示2
    服务端向客户端回写数据

    客户端:

    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.InetAddress;
    import java.net.Socket;
    
    public class TCPClient {
        public static void main(String[] args){
            Socket socket = null;
            OutputStream os = null;
            ByteArrayOutputStream baos=null;
            InputStream is=null;
            try {
                //1、创建Socket对象,它的第一个参数需要的是服务端的IP,第二个参数是服务端的端口
                InetAddress inet = InetAddress.getByName("127.0.0.1");
                socket = new Socket(inet,8888);
                //2、获取一个输出流,用于写出要发送的数据
                os = socket.getOutputStream();
                //3、写出数据
                os.write("你好,我是客户端!".getBytes());
                //==========================解析回复==================================
                //4、首先必须通知服务器,我已经输出完毕了,不然服务端不知道什么时候输出完毕
                //服务端的while循环会一直执行,会阻塞
                socket.shutdownOutput();
                ///5、获取输入流,用于读取服务端回复的数据
                is = socket.getInputStream();
                baos = new ByteArrayOutputStream();
                int len=0;
                byte[] buffer = new byte[1024];
                while ((len=is.read(buffer))!=-1){
                    baos.write(buffer,0,len);
                }
                System.out.println("收到了来自服务端的消息:"+baos.toString());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {//6、释放资源
                if(socket!=null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(os!=null){
                    try {
                        os.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(is!=null){
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (baos!=null){
                    try {
                        baos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    服务端:

    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class TCPServer {
        public static void main(String[] args) {
            ServerSocket serverSocket = null;
            Socket socket = null;
            InputStream is = null;
            ByteArrayOutputStream baos = null;
            OutputStream os=null;
            try {
                //1、创建服务端的ServerSocket,指明自己的端口号
                serverSocket = new ServerSocket(8888);
                //2、调用accept接收到来自于客户端的socket
                socket = serverSocket.accept();//阻塞式监听,会一直等待客户端接入
                //3、获取socket的输入流
                is = socket.getInputStream();
    
    //        不建议这样写:因为如果我们发送的数据有汉字,用String的方式输出可能会截取汉字,产生乱码
    //        int len=0;
    //        byte[] buffer = new byte[1024];
    //        while ((len=is.read(buffer))!=-1){
    //            String str = new String(buffer, 0, len);
    //            System.out.println(str);
    //        }
    
                //4、读取输入流中的数据
                //ByteArrayOutputStream的好处是它可以根据数据的大小自动扩充
                baos = new ByteArrayOutputStream();
                int len=0;
                byte[] buffer = new byte[1024];
                while ((len=is.read(buffer))!=-1){
                    baos.write(buffer,0,len);
                }
                System.out.println("收到了来自于客户端"+socket.getInetAddress().getHostName()
                        +"的消息:"+baos.toString());
                //===========================回复==========================================
                //5、获取一个输出流,写出回复给客户端
                os = socket.getOutputStream();
                //6、写出数据
                os.write("你好,我是服务端".getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {//7、关闭资源
                if(serverSocket!=null){
                    try {
                        serverSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(socket!=null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(is!=null){
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(baos!=null){
                    try {
                        baos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(os!=null){
                    try {
                        os.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    在这里插入图片描述
    在这里插入图片描述
    案例演示3
    上传文件:客户端发送文件给服务端,服务端将文件保存在本地
    在这里插入图片描述

    客户端:

    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.InetAddress;
    import java.net.Socket;
    
    public class TCPClient {
        public static void main(String[] args) {
            Socket socket = null;
            FileInputStream fis = null;
            OutputStream os = null;
            try {
                //1、创建Socket对象,它的第一个参数需要的是服务端的IP,第二个参数是服务端的端口
                InetAddress inet = InetAddress.getByName("127.0.0.1");
                socket = new Socket(inet, 8888);
                //2、创建一个文件输入流,读取要上传的文件
                fis = new FileInputStream("D:/test/touxiang.jpg");
                //3、获取一个输出流,用于写出要发送的数据
                os = socket.getOutputStream();
                byte[] buffer = new byte[1024];
                int len=0;
                while((len=fis.read(buffer))!=-1){
                    //4、写出数据
                    os.write(buffer,0,len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {//5、释放资源
                if(socket!=null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(fis!=null){
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(os!=null){
                    try {
                        os.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    服务端:

    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class TCPServer {
        public static void main(String[] args) {
            ServerSocket serverSocket = null;
            Socket socket = null;
            FileOutputStream fos = null;
            InputStream is = null;
            try {
                //1、创建服务端的ServerSocket,指明自己的端口号
                serverSocket = new ServerSocket(8888);
                //2、调用accept接收到来自于客户端的socket
                socket = serverSocket.accept();//阻塞式监听,会一直等待客户端的接入
                //3、创建一个文件输出流,用于将读取到的客户端上传的文件输出
                fos = new FileOutputStream("touxiang.jpg");
                //4、获取socket的输入流
                is = socket.getInputStream();
                byte[] buffer = new byte[1024];
                int len=0;
                while((len=is.read(buffer))!=-1){
                    fos.write(buffer,0,len);//5、写出文件
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {//6、释放资源
                if(serverSocket!=null){
                    try {
                        serverSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(socket!=null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(fos!=null){
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(is!=null){
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

    假设大海里有许多岛屿,客户端和服务端相当于其中的两座岛屿,“客户端”岛屿生产了一种农作物要运到“服务端”岛屿,所以“客户端”要知道“服务端”确切的地址(IP),不然就运错地方了,socket就相当于运输的船只,port就相当于“服务端”岛屿的某个港口。

    (二)UDP网络编程

    从技术意义上来讲,只有TCP才会分Server和Client。对于UDP来说,严格意义上,并没有所谓的Server和Client。
    java.net包给我们提供了两个类DatagramSocket(此类表示用于发送和接收数据报的套接字)和DatagramPacket(该类表示数据报的数据包。 )

    1.DatagramSocket

    (1)构造方法摘要

    protected DatagramSocket()构造数据报套接字并将其绑定到本地主机上的任何可用端口。
    protected DatagramSocket(int port)构造数据报套接字并将其绑定到本地主机上的指定端口。
    protected DatagramSocket(int port, InetAddress laddr)创建一个数据报套接字,绑定到指定的本地地址。

    2.DatagramPacket

    (1)构造方法摘要

    DatagramPacket(byte[] buf, int offset, int length)构造一个 DatagramPacket用于接收指定长度的数据报包到缓冲区中。
    DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)构造用于发送指定长度的数据报包到指定主机的指定端口号上。

    (2)常用方法摘要

    byte[] getData() 返回数据报包中的数据。
    InetAddress getAddress() 返回该数据报发送或接收数据报的计算机的IP地址。
    int getLength() 返回要发送的数据的长度或接收到的数据的长度。

    3.代码实现

    案例演示1
    发送方:

    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    
    public class UDPSender {
        public static void main(String[] args) throws IOException {
            //1、创建一个socket
            DatagramSocket socket = new DatagramSocket();
            InetAddress inet = InetAddress.getLocalHost();
            String msg="你好,很高兴认识你!";
            byte[] buffer = msg.getBytes();
            //2、创建一个包(要发送给谁)
            DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length,inet,9090);
            //3、发送包
            socket.send(packet);
            //4、释放资源
            socket.close();
        }
    }
    

    接收方:

    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    
    public class UDPReceiver {
        public static void main(String[] args) throws IOException {
            //1、创建一个socket,开放端口
            DatagramSocket socket = new DatagramSocket(9090);
            byte[] buffer = new byte[1024];
            //2、创建一个包接收数据
            DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
            //3、接收数据
            socket.receive(packet);//阻塞式接收
            //将数据包转换为字符串输出
            String msg = new String(packet.getData(), 0, packet.getLength());
            System.out.println(msg);
            //4、释放资源
            socket.close();
        }
    }
    

    在这里插入图片描述
    注意
    如果是TCP中先启动客户端会报错:
    在这里插入图片描述
    而如果是UDP中先启动发送方不会报错,但会正常退出。

    案例演示2
    完成在线咨询功能,学生和老师在线一对一交流(多线程

    发送方:

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.SocketException;
    
    public class UDPSender implements Runnable{
        //创建一个socket
        DatagramSocket socket=null;
        //创建一个流 用于录入键盘的数据
        BufferedReader bfr=null;
        //发送数据目的地的IP
        private String toIP;
        //发送数据目的地的端口
        private int toPort;
    
        public UDPSender(String toIP, int toPort) {
            this.toIP = toIP;
            this.toPort = toPort;
            try {
                socket=new DatagramSocket();//创建一个socket
            } catch (SocketException e) {
                e.printStackTrace();
            }
            bfr=new BufferedReader(new InputStreamReader(System.in));//从键盘录入数据到流中
        }
    
        @Override
        public void run() {
            while (true){//循环发送数据
                try {
                    String msg = bfr.readLine();//从流中读取数据
                    byte[] buffer = msg.getBytes();
                    InetAddress inet = InetAddress.getByName(toIP);
                    DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length, inet, toPort);
                    socket.send(packet);
                    //如果发送了拜拜,则退出发送
                    if(msg.equals("拜拜")){
                        break;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //释放资源
            if(socket!=null){
                socket.close();
            }
            if (bfr!=null){
                try {
                    bfr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    接收方:

    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.SocketException;
    
    public class UDPReceiver implements Runnable{
        //创建一个socket
        DatagramSocket socket=null;
        //接收方自己所在的端口
        private int fromPort;
        //数据发送者的姓名
        private String msgFrom;
    
        public UDPReceiver(int fromPort,String msgFrom) {
            this.fromPort = fromPort;
            this.msgFrom=msgFrom;
            try {
                socket=new DatagramSocket(fromPort);//创建一个socket
            } catch (SocketException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void run() {
            while(true){//循环接收
                try {
                    byte[] buffer = new byte[1024 * 8];
                    DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
                    socket.receive(packet);
                    String msg = new String(packet.getData(), 0, packet.getLength());
                    System.out.println(msgFrom+":"+msg);
                    if (msg.equals("拜拜")){//如果接收到的数据为拜拜,则退出接收
                        break;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //释放资源
            socket.close();
        }
    }
    

    学生线程:

    public class Student {
        public static void main(String[] args) {
            new Thread(new UDPSender("127.0.0.1",8888)).start();
            new Thread(new UDPReceiver(7777,"老师")).start();
        }
    }
    

    老师线程:

    public class Teacher {
        public static void main(String[] args) {
            new Thread(new UDPSender("127.0.0.1",7777)).start();
            new Thread(new UDPReceiver(8888,"学生")).start();
        }
    }
    

    学生的窗口:
    在这里插入图片描述
    老师的窗口:
    在这里插入图片描述

    六、URL

    (一)概念

    URL(Uniform Resource Locator)统一资源定位符,它表示Internet上某一资源的地址。
    通过URL我们可以访问Internet上的各种网络资源,比如最常见的www,ftp站点。浏览器通过解析给定的URL可以在网络上查找相应的文件或其他资源。

    URI=URL+URN

    • URI:Uniform Resource Identifier ,统一资源标志符。
    • URL:Uniform Resource Locator,统一资源定位符。
    • URN:Uniform Resource Name,统一资源命名。

    网络三大基石:HTML,HTTP,URL

    (二)格式

    URL的基本结构由5部分组成:
    <传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表

    • 片段名:即锚点,例如看小说,直接定位到章节
    • 参数列表格式:参数名=参数值&参数名=参数值......

    例如:
    http://localhost:8080/index.jsp#a?username=Tom&password=123456

    (三)URL类

    java.net包下

    1.构造方法摘要

    URL(String spec)根据 String 表示形式创建 URL 对象。
    URL(String protocol, String host, int port, String file) 根据指定协议名、主机名、端口号和文件名创建 URL 对象。
    URL(String protocol, String host, String file) 根据指定的协议名、主机名和文件名创建 URL。

    2.常用方法摘要

    String getProtocol()获取此 URL的协议名称。
    String getHost() 获取此 URL 的主机名。
    int getPort() 获取此 URL 的端口号。
    String getPath() 获取此 URL 的文件路径。
    String getFile()获取此 URL 的文件名。
    String getQuery()获取此 URL的查询部分。
    URLConnection openConnection() 返回一个URLConnection实例,表示与URL引用的远程对象的URL 。

    • URLConnection类中又有一个方法:
      InputStream getInputStream() 返回从此打开的连接读取的输入流。

    案例演示1

    import java.net.MalformedURLException;
    import java.net.URL;
    
    public class Test {
        public static void main(String[] args) throws MalformedURLException {
            URL url = new URL("http://localhost:8080/index.jsp?username=Tom&password=123456");
            System.out.println(url.getProtocol());//获取协议名
            System.out.println(url.getHost());//获取主机名
            System.out.println(url.getPort());//获取端口号
            System.out.println(url.getPath());//获取文件路径
            System.out.println(url.getFile());//获取文件名
            System.out.println(url.getQuery());//获取查询名
        }
    }
    

    在这里插入图片描述
    案例演示2
    URL下载网络资源

    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    public class Test {
        public static void main(String[] args) throws IOException {
            //下载地址
            URL url = new URL("https://img.t.sinajs.cn/t6/style/images/global_nav/WB_logo.png?id=1404211047727");
            //连接到这个资源 HTTP
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            InputStream is = urlConnection.getInputStream();
            FileOutputStream fos = new FileOutputStream("weibo.jpg");
            byte[] buffer = new byte[1024];
            int len=0;
            while ((len=is.read(buffer))!=-1){
                fos.write(buffer,0,len);
            }
            //释放资源
            urlConnection.disconnect();//断开连接
            is.close();
            fos.close();
        }
    }
    

    小结

    在这里插入图片描述

    展开全文
  • Java网络编程-第三版(中文版).pdf(Elliotte Rusty Harold)
  • Java网络编程

    千次阅读 多人点赞 2020-11-28 17:29:17
    Java网络编程 1、网络编程 1.1、概述 1、计算机网络是通过传输介质、通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来,实现资源共享和数据传输的系统。网络编程就就是编写程序使联网的两个(或多个)...

    Java网络编程

    1、网络编程

    1.1、概述

    1、计算机网络是通过传输介质、通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来,实现资源共享和数据传输的系统。网络编程就就是编写程序使联网的两个(或多个)设备(例如计算机)之间进行数据传输。Java语言对网络编程提供了良好的支持,通过其提供的接口我们可以很方便地进行网络编程。

    2、JavaInternet 上的语言,它从语言级上提供了对网络应用程 序的支持,程序员能够很容易开发常见的网络应用程序。

    3、Java提供的网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在 Java 的本机安装系统里,由 JVM 进行控制。并 且 Java 实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境

    1.2、计算机网络基础

    1、概念

        把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息、 共享硬件、软件、数据信息等资源。

        计算机网络是计算机专业必修的一门学科!里面涉及到计算机之间的通信、网络安全等方方面面,有时间可以自行去学习,关于更多的网络基础知识这里就不一一介绍了。

    推荐文章:https://www.jianshu.com/p/ae5e1cee5b04

    2、网络编程的目的

        直接或间接地通过网络协议与其它计算机实现数据交换,进行通讯。

    3、网络编程中有两个主要的问题

        ①如何准确地定位网络上一台或多台主机;定位主机上的特定的应用

        ②找到主机后如何可靠高效地进行数据传输

    1.3、网络通信要素概述

    1、我们需要知道的是主机间通过网络进行通信是需要遵循网络通信协议,是通过IP地址准确定位主机,通过端口号准确定位主机上的应用。

    IP地址和端口号

    网络通信协议

    2、如何实现网络中的主机互相通信?

    ① 通信双方地址:IP端口号

    ② 一定的规则(即:网络通信协议。有两套参考模型)

        OSI参考模型:模型过于理想化,未能在因特网上进行广泛推广。

        TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。

    3、网络通信协议(以TCP/IP模型为例)

    TCP/IP,即Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议,是Internet最基本的协议、Internet国际互联网络的基础。
    在这里插入图片描述

    1.4、IP地址和端口号(组合就是网络套接字)

    我们知道IP地址和端口号是通信要素之一,它们可以唯一确定某一台主机的某个应用,并为主机之间通信提供了可能!那么什么是IP地址和端口号呢?

    1、IP 地址:InetAddress(在Java中使用InetAddress类代表IP)

    • 一的标识 Internet 上的计算机(通信实体)

    • 本地回环地址(hostAddress):127.0.0.1 主机名(hostName):localhost

    • P地址分类方式1:IPV4IPV6

    • IPV4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。2011年初已 经用尽。以点分十进制表示,如192.168.0.1

    • IPV6:128位(16个字节),写成8个无符号整数,每个整数用四个十六进制位表示, 数之间用冒号(:)分开,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984

    • IP地址分类方式2:公网地址(万维网使用)和私有地址(局域网使用)。192.168. 开头的就是私有址址,范围即为192.168.0.0–192.168.255.255,专门为组织机 构内部使用

    • 特点:不易记忆

    2、InetAddress类

    Internet上的主机有两种方式表示地址:

        ①域名(hostName):www.baidu.com

        ②IP 地址(hostAddress):14.215.177.38

    InetAddress类主要表示IP地址,两个子类:Inet4Address、Inet6Address

    InetAddress 类对象含有一个 Internet 主机地址的域名和IP地址:www.baidu.com 和 14.215.177.38

    域名容易记忆,当在连接网络时输入一个主机的域名后,域名服务器(DNS) 负责将域名转化成IP地址,这样才能和主机建立连接。 -------域名解析

    /*
    1 java中使用InetAddress代表IP
    2 IP的分类:IPV4和IPV6     万维网和局域网
    
    3 域名:www.baidu.com www.cnblogs.com
    
    4 本地回路地址:127.0.0.1 对应着:localhost
    
    5 如何实例化InetAddress类的对象,两个静态方法:
        InetAddress getByName(String host)
        InetAddress getLocalHost()
    
    6 两个常用方法
        getHostName()
        getHostAddress()
    
    7 端口号:正在计算机上运行的进程
     */
    public class InetAddressTest {
        public static void main(String[] args){
            try {
                // File file = new File("test.txt");
                InetAddress IP1 = InetAddress.getByName("192.168.3.2");
                System.out.println(IP1);
    
                InetAddress IP2 = InetAddress.getByName("www.baidu.com");
                System.out.println(IP2);
                // 获取本地IP
                InetAddress localHost = InetAddress.getLocalHost();
                System.out.println(localHost);
    
                // getHostName()
                System.out.println(IP2.getHostName());
                // getHostAddress()
                System.out.println(IP2.getHostAddress());
    
    
            } catch(UnknownHostException e){
                e.printStackTrace();
            }
        }
    }
    

    3、端口号

    • 端口号就是标识正在计算机上运行的进程(程序)
    • 不同的进程有不同的端口号
    • 被规定为一个 16 位的整数 0~65535。

    端口分类:

    ① 公认端口:0~1023。被预先定义的服务通信占用(如:HTTP占用端口 80,FTP占用端口21,Telnet占用端口23)

    ② 注册端口:1024~49151。分配给用户进程或应用程序。(如:Tomcat占 用端口8080,MySQL占用端口3306,Oracle占用端口1521等)。

    ③ 动态/私有端口:49152~65535
    在这里插入图片描述
    4、端口号与IP地址的组合得出一个网络套接字:Socket

    1.5、网络协议

    1、网络通信协议

        计算机网络中实现通信必须有一些约定,即通信协议,对速率、传输代码、代 码结构、传输控制步骤、出错控制等制定标准。

    2、问题:网络协议太复杂

        计算机网络通信涉及内容很多,比如指定源地址和目标地址,加密解密,压缩 解压缩,差错控制,流量控制,路由控制,如何实现如此复杂的网络协议呢?

    3、通信协议分层的思想

        在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常 用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与 再下一层不发生关系。各层互不影响,利于系统的开发和扩展。

    4、TCP/IP协议簇

    传输层协议中有两个非常重要的协议:

    • 传输控制协议TCP(Transmission Control Protocol)
    • 户数据报协议UDP(User Datagram Protocol)

    TCP/IP 以其两个主要协议:传输控制协议(TCP)和网络互联协议(IP)而得 名,实际上是一组协议,包括多个具有不同功能且互为关联的协议。

    IP(Internet Protocol)协议是网络层的主要协议,支持网间互连的数据通信。

    TCP/IP协议模型从更实用的角度出发,形成了高效的四层体系结构,即物理链路层、IP层、传输层和应用层。

    5、TCP 和 UDP

    TCP协议:

    ✔ 使用TCP协议前,须先建立TCP连接,形成传输数据通道
    
    ✔ 传输前,采用“三次握手”方式,点对点通信,是可靠的
    
    ✔ TCP协议进行通信的两个应用进程:客户端、服务端。
    
    ✔ 在连接中可进行大数据量的传输
    
    ✔ 传输完毕,需释放已建立的连接,效率低
    

    UDP协议:

    ✔ 将数据、源、目的封装成数据包,不需要建立连接
    
    ✔ 每个数据报的大小限制在64K内
    
    ✔ 发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
    
    ✔ 可以广播发送
    
    ✔ 发送数据结束时无需释放资源,开销小,速度快
    

    1.6、三次握手与四次挥手

    1、三次握手
    三次握手

    1. 第一步,请求端(客户端)发送一个包含SYN标志的TCP报文,SYN即同步(Synchronize),同步报文会指明客户端使用的端口以及TCP连接的初始序号;

    2. 第二步,服务器在收到客户端的SYN报文后,将返回一个SYN+ACK的报文,表示客户端的请求被接受,同时TCP序号被加一,ACK即确认(Acknowledgment)。

    3. 第三步,客户端也返回一个确认报文ACK给服务器端,同样TCP序列号被加一,到此一个TCP连接完成。

    2、四次挥手
    四次挥手
    由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

    1. TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。
    2. 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
    3. 服务器关闭客户端的连接,发送一个FIN给客户端。
    4. 客户端发回ACK报文确认,并将确认序号设置为收到序号加1。

    2、TCP网络编程

    2.1、Socket介绍

    1、利用套接字(Socket)开发网络应用程序早已被广泛的采用,以至于成为事实 上的标准。

    2、网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。

    3、通信的两端都要有Socket,是两台机器间通信的端点。

    4、网络通信其实就是Socket间的通信。

    5、Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。

    6、一般主动发起通信的应用程序属客户端,等待通信请求的为服务端。

    7、Socket分类:

    1. 流套接字(stream socket):使用TCP提供可依赖的字节流服务

    2. 数据报套接字(datagram socket):使用UDP提供“尽力而为”的数据报服务

    2.2、基于Socket的TCP编程

    1、Java语言的基于套接字编程分为服务端编程和客户端编程,其通信模型如图所示
    基于Socket的TCP编程
    2、客户端Socket的工作过程包含以下四个基本的步骤:

    1. 创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务端的通信路线。若连接失败,则会出现异常。

    2. 打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用 getOutputStream()方法获得输出流,进行数据传输

    3. 按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入路线的信息),通过输出流将信息写入线程

    4. 关闭 Socket:断开客户端到服务器的连接,释放线路

    3、客户端创建Socket对象:

    客户端程序可以使用Socket类创建对象,创建的同时会自动向服务器方发起连 接。Socket的构造器是:

    // 构造器一
    Socket(String host,int port)throws UnknownHostException,IOException
    /* 向服务器(域名是 host。端口号为port)发起TCP连接,若成功,则创建Socket对象,否则抛出异常。*/
    
    // 构造器二
    Socket(InetAddress address,int port)throws IOException
    /* 根据InetAddress对象所表示的 IP地址以及端口号port发起连接。*/
    

    客户端建立socketAtClient对象的过程就是向服务器发出套接字连接请,简要步骤如下

    Socket s = new Socket("192.168.40.165",9999); // 1、创建Socket对象,指明服务端的IP和端口号
    OutputStream out = s.getOutputStream(); // 2、获取一个输出流,用于输出数据
    out.write("hello".getBytes()); // 3、写出数据
    s.close(); // 4、回收资源
    

    4、服务器(服务端)程序的工作过程包含以下四个基本的步骤:

    1. 调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口 上。用于监听客户端的请求。

    2. 调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信 套接字对象。

    3. 调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出 流和输入流,开始网络数据的发送和接收。

    4. 关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。

    5、服务器建立 ServerSocket 对象

    1. ServerSocket 对象负责等待客户端请求建立套接字连接,类似邮局某个窗口 中的业务员。也就是说,服务器必须事先建立一个等待客户请求建立套接字 连接的ServerSocket对象。

    2. 所谓“接收”客户的套接字请求,就是accept()方法会返回一个 Socket 对象

    ServerSocket ss = new ServerSocket(9999); // 1、创建服务端的ServerSocket,指明自己的端口号
    Socket s = ss.accept (); // 2、调用accept()监听来自客户端的连接
    InputStream in = s.getInputStream(); // 3、获取输入流,读取输入流的数据
    byte[] buf = new byte[1024]; 
    int num = in.read(buf); 
    String str = new String(buf,0,num); 
    System.out.println(s.getInetAddress().toString()+":"+str); 
    s.close(); // 4、回收资源
    ss.close();
    

    2.3、TCP编程简单C/S通信示例

    /**
     * @description: TCP编程,模拟基于C/S架构客户端与服务端间的通信
     * @author: laizhenghua
     * @date: 2020/11/28 20:08
     */
    public class SocketTest {
        /* 客户端 */
        @Test
        public void client(){
            OutputStream output = null;
            Socket socket = null;
            try {
                InetAddress localHost = InetAddress.getByName("127.0.0.1");
                socket = new Socket(localHost,8848);
                output = socket.getOutputStream();
                output.write("hello I'm the client".getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(output != null){
                    try {
                        output.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(socket != null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        /* 服务端 */
        @Test
        public void server() {
            ServerSocket serverSocket = null;
            Socket socket = null;
            InputStream input = null;
            ByteArrayOutputStream out = null;
            try {
                serverSocket = new ServerSocket(8848);
                socket = serverSocket.accept();
                System.out.println("client IP: " + socket.getInetAddress());
                input = socket.getInputStream();
                /*
                一般不建议这样书写,数据传输时可能会出现乱码!!
                byte[] buffer = new byte[1024];
                int len;
                while((len = input.read(buffer)) != -1){
                    String data = new String(buffer,0,len);
                    System.out.println(data);
                }*/
    
                out = new ByteArrayOutputStream();
                byte[] buffer = new byte[10];
                int len;
                while((len = input.read(buffer)) != -1){
                    out.write(buffer,0,len);
                }
                System.out.println(out.toString());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(out != null){
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(input != null){
                    try {
                        input.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();
                    }
                }
            }
        }
    }
    

    2.4、TCP编程实现C/S文件传输

    实现功能:客户端发送文件给服务端,服务端将文件保存在本地。

    /**
     * @description: TCP编程,客户端发送文件给服务端,服务端将文件保存在本地。
     * @author: laizhenghua
     * @date: 2020/11/28 20:08
     */
    public class TCPSocketTest {
    	/* 客户端 */
        @Test
        public void client() {
            Socket socket = null;
            OutputStream writer = null;
            BufferedInputStream bis = null;
            try {
                socket = new Socket(InetAddress.getByName("127.0.0.1"),8089);
                writer = socket.getOutputStream();
    
                bis = new BufferedInputStream(new FileInputStream(new File("me.jpg")));
                byte[] buffer = new byte[1024];
                int len;
                while((len = bis.read(buffer)) != -1){
                    writer.write(buffer,0,len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(socket != null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(writer != null){
                    try {
                        writer.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(bis != null){
                    try {
                        bis.close();
                        System.out.println("发送成功!");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    	/* 服务端 */
        @Test
        public void server() throws IOException { // 这里异常应该使用try-catch-finally
            ServerSocket socket = new ServerSocket(8089);
            System.out.println("正在等待客户端连接...");
            Socket clientSocket = socket.accept();
    
            System.out.println("客户端已连接IP地址为:"+clientSocket.getInetAddress().getHostName());
            InputStream is = clientSocket.getInputStream();
            BufferedOutputStream reader = new BufferedOutputStream(new FileOutputStream(new File("new_me.jpg")));
    
            byte[] buffer = new byte[1024];
            int len;
            while((len = is.read(buffer)) != -1){
                reader.write(buffer,0,len);
            }
            System.out.println("接收成功");
    
            socket.close();
            clientSocket.close();
            is.close();
            reader.close();
        }
    }
    

    2.5、TCP编程实现C/S信息反馈

    实现功能:从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给 客户端。并关闭相应的连接。

    /**
     * @description: TCP编程,从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给 客户端。并关闭相应的连接。
     * @author: laizhenghua
     * @date: 2020/11/28 20:08
     */
    public class TCPSocketTest2 {
    	/* 客户端 */
        @Test
        public void client() {
            Socket socket = null;
            OutputStream writer = null;
            BufferedInputStream bis = null;
            try {
                socket = new Socket(InetAddress.getByName("127.0.0.1"),8089);
                writer = socket.getOutputStream();
    
                bis = new BufferedInputStream(new FileInputStream(new File("me.jpg")));
                byte[] buffer = new byte[1024];
                int len;
                while((len = bis.read(buffer)) != -1){
                    writer.write(buffer,0,len);
                }
                // 关闭数据的输出
                socket.shutdownOutput();
    
                // 接收服务端反馈的信息并输出到控制台
                InputStream is = socket.getInputStream();
                ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
                byte[] buf = new byte[10];
                int l;
                while((l = is.read(buf)) != -1){
                    byteArray.write(buf,0,l);
                }
                System.out.println(byteArray.toString());
                is.close();
                byteArray.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if(socket != null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(writer != null){
                    try {
                        writer.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(bis != null){
                    try {
                        bis.close();
                        System.out.println("发送成功!");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    	/* 服务端 */
        @Test
        public void server() throws IOException { // 这里异常应该使用try-catch-finally
            ServerSocket socket = new ServerSocket(8089);
            System.out.println("正在等待客户端连接...");
            Socket clientSocket = socket.accept();
    
            System.out.println("客户端已连接IP地址为:"+clientSocket.getInetAddress().getHostName());
            InputStream is = clientSocket.getInputStream();
            BufferedOutputStream reader = new BufferedOutputStream(new FileOutputStream(new File("new_me.jpg")));
    
            byte[] buffer = new byte[1024];
            int len;
            while((len = is.read(buffer)) != -1){
                reader.write(buffer,0,len);
            }
            System.out.println("接收成功");
    
            // 服务端给客户端反馈信息
            OutputStream os = clientSocket.getOutputStream();
            os.write("你好客户端,照片已经收到".getBytes());
    
            socket.close();
            clientSocket.close();
            is.close();
            reader.close();
            os.close();
        }
    }
    

    3、UDP网络编程

    3.1、UDP网络通信

    1、类 DatagramSocketDatagramPacket 实现了基于 UDP 协议网络程序。

    2、UDP数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证 UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。

    3、DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。

    4、UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接。如同发快递包裹一样。

    3.2、UDP网络通信流程

    1、DatagramSocket与DatagramPacket

    2、建立发送端,接收端

    3、建立数据包

    4、调用Socket的发送、接收方法

    5、关闭Socket

    注意:发送端与接收端是两个独立的运行程序

    3.3、UDP网络通信代码实现

    /*
    UDP网络编程:
        ✔ 将数据、源、目的封装成数据包,不需要建立连接
        ✔ 每个数据报的大小限制在64K内
        ✔ 发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
        ✔ 可以广播发送
        ✔ 发送数据结束时无需释放资源,开销小,速度快
     */
    public class UDPSocketTest {
        @Test // 发送端
        public void send() throws IOException {
            DatagramSocket socket = new DatagramSocket();
    
            byte[] data = "hello world".getBytes();
            DatagramPacket packet = new DatagramPacket(data,0,data.length, InetAddress.getLocalHost(),8080);
    
            socket.send(packet);
    
            socket.close();
        }
    
        @Test // 接收端
        public void receiver() throws IOException {
            DatagramSocket socket = new DatagramSocket(8080);
    
            byte[] buffer = new byte[100];
            DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
    
            socket.receive(packet);
    
            System.out.println(new String(packet.getData(),0,packet.getLength()));
    
            socket.close();
        }
    }
    

    4、URL网络编程

    4.1、URL介绍

    1、URL(Uniform Resource Locator):统一资源定位符,它表示 Internet 上某一 资源的地址。

    2、它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate 这个资源。

    3、通过 URL 我们可以访问 Internet 上的各种网络资源,比如最常见的 www,ftp 站点。浏览器通过解析给定的 URL 可以在网络上查找相应的文件或其他资源。

    4、URL的基本结构由5部分组成: <传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表

    1. 例如: http://192.168.1.100:8080/helloworld/index.jsp#a?username=shkstart&password=123

    2. #片段名:即锚点,例如看小说,直接定位到章节

    3. 参数列表格式:参数名=参数值&参数名=参数值…

    5、Restful风格

    一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。restful风格在实际开发中使用较多,对于URL地址有全新的使用方式,可以自行了解restful风格的使用!

    推荐文章:https://blog.csdn.net/m0_46357847/article/details/109753731

    4.2、URL类与类的构造器

    1、为了表示URL,java.net 中实现了类 URL。我们可以通过下面的构造器来初 始化一个 URL 对象:

    1. public URL (String spec):通过一个表示URL地址的字符串可以构造一个URL对象。例如:URL url = new URL ("https://www.baidu.com/");

    2. public URL(URL context, String spec):通过基 URL 和相对 URL 构造一个 URL 对象。 例如:URL downloadUrl = new URL(url, “download.html");

    3. public URL(String protocol, String host, String file); 例如:new URL(“http”, “www.atguigu.com”, “download. html");

    4. public URL(String protocol, String host, int port, String file); 例如: URL gamelan = new URL(“http”, “www.atguigu.com”, 80, “download.html");

    2、URL类的构造器都声明抛出非运行时异常,必须要对这一异常进行处理,通 常是用 try-catch 语句进行捕。

    4.3、URL类常用方法

    一个URL对象生成后,其属性是不能被改变的,但可以通过它给定的方法来获取这些属性:

    1. public String getProtocol( ) 获取该URL的协议名

    2. public String getHost( ) 获取该URL的主机名

    3. public String getPort( ) 获取该URL的端口号

    4. public String getPath( ) 获取该URL的文件路径

    5. public String getFile( ) 获取该URL的文件名

    6. public String getQuery( ) 获取该URL的查询名

    end

    Thanks for watching

    end

    展开全文
  • java网络编程精解

    2017-11-02 14:18:54
    Java网络编程精解》结合大量的典型实例,详细介绍了用Java来编写网络应用程序的技术。《Java网络编程精解》的范例都基于最新的JDK 1.5版本,书中内容包括:Java网络编程的基础知识、套接字编程、非阻塞通信、创建...
  • JAVA 网络编程服务器端例程,一个测试socket通信的比较好的例程
  • 本书的范例都基于最新的JDK 1.5版本,书中内容包括:Java网络编程的基础知识、套接字编程、非阻塞通信、创建HTTP服务器与客户程序、数据报通信、对象的序列化与反序列化、Java反射机制、RMI框架、JDBC API、JavaMail...
  • 前几天看到公司一个大神看技术文档,打眼瞟了一下,全是英文的表示直接看看不到。但是大神不一样,人家是硕士哦,英文杠杠的,但是自己心里也想看...java网络编程第四版 java_concurrency_in_practice.pdf Java并发实践
  • JAVA网络编程 第4版

    2018-05-04 11:26:13
    JAVA网络编程 第4版 JAVA网络编程 第4版 JAVA网络编程 第4版
  • java网络编程.zip

    2019-05-12 12:07:28
    java网络编程.zip 北邮计算机网络编程的全套课件。适合自学java网络编程
  • 该资源包含了java网络编程的基本思想以及详细教程,在此基础上给出视频演示和讲解使得初学者更容易上手,而且资源给出了编程的全部源码,初学者可以自己运行,深入了解网络编程的实质。
  • java网络编程模式1---马克-to-win Java视频的详细介绍
  • Java网络编程(第4版)

    2019-01-04 10:00:27
    Java网络编程(第4版)。《Java网络编程(第4版)。《Java网络编程(第4版)。
  • java网络编程基础

    2018-03-19 21:33:51
    java网络编程基础 java网络编程基础 java网络编程基础
  • 牛逼的东西,自己手写的,正常运行,请尽快下载。
  • java网络编程基础习题+部分答案(这里面的答案是正确的)
  • Java网络编程 JAVA web开发实例讲解 宠物分类展现web项目 第01章 项目背景知识(共15页).ppt Java网络编程 JAVA web开发实例讲解 宠物分类展现web项目 第02章 用HTML+CSS实现宠物分类展现静态网页版本(共44页)....
  • Java网络编程

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 446,666
精华内容 178,666
关键字:

java网络编程

java 订阅