超基础的网络编程01:基础知识

网络编程01:基础知识

标签: 网络编程


网络编程概述

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

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

之前学习的计算机网络的知识,只学习了理论,并没有自己动手去实验。Java网络编程将会重新复习这部分知识

网络基础概述

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

网络编程的目的:
直接或间接地通过网络协议与其它计算机进行通讯。

网络编程中有两个主要的问题:
1. 如何准确地定位网络上一台或多台主机
2. 找到主机后如何可靠高效地进行数据传输。

网络通信协议

在网络中通过通信双方的主机地址互相通信,并且需要一定的规则,这个规则就是网络通信协议。

有两套参考模型:

  • OSI参考模型:模型过于理想化,未能在因特网上进行广泛推广
  • TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。

此处输入图片的描述

其中我们主要是研究涉及到网络编程的部分:

  • 网络层 :IP(网络之间的互联协议)

  • 传输层:TCP(传输控制协议)、UDP(用户数据报协议)

  • 应用层:Telnet(Internet远程登录服务的标准协议和主要方式)、FTP(文本传输协议)、HTTP(超文本传送协议)

其中传输层是我们研究的重点:

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

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

TCP/IP 以其两个主要协议:传输控制协议(TCP)和网络互联协议(IP)而得名,实际上是一组协议,包括多个具有不同功能且互为关联的协议。
IP(Internet Protocol)协议是网络层的主要协议,支持网间互连的数据通信。
TCP/IP协议模型从更实用的角度出发,形成了高效的四层体系结构,即物理链路层、IP层、传输层和应用层。

通信要素

IP

网络通信的第一个要素:ip地址。通过ip地址,唯一的定位互联网上的一台主机。

ip地址用于唯一标识网络中的一个通信实体,这个通信实体可以是一台主机,可以是一台打印机,或者是路由器的某一个端口。而在基于IP协议网络中传输的数据包,必须使用IP地址来进行标示。ip地址就像写一封信,必须指定收件人的地址一样。每个被传输的数据包中都包括了一个源IP和目标IP。

在Java中,IP 地址对应的包是位于java.net包下的InetAddress类

InetAddress类

public class InetAddress extends Object implements Serializable

InetAddress类用来封装数字式的IP地址和该地址的域名。通过一个IP主机名与这个类发生作用,IP主机名比它的IP地址用起来更简便更容易理解。一般地讲,它包括一个主机名和一个IP地址。

InetAddress用来代表IP地址。一个InetAddress的对象就代表着一个IP地址。InetAddress类内部隐藏了地址数字。

值得注意的是:
InetAddress类没有明显的构造函数。为生成一个InetAddress对象,必须运用一个可用的工厂方法来创建一个对象来连接到DNS服务器来解析主机名(工厂方法仅是一个类中静态方法返回一个该类实例的约定)。

可以通过下面的静态方法来创建InetAddress类的实例:

  • static InetAddress getByName(String host)
    返回一个传给它的主机名的InetAddress。这个方法实际返回两个地址,具体返回哪一个是不确定的。如果出于某种原因你需要得到一个主机的所有地址,可以调用getAllByName()。
    这个方法并不只是设置InetAddress类中的一个私有String字段。实际上它会建立与本地DNS服务器的一个连接,来查找名字和数字地址(如果你之前查找过这个主机,这个信息可能会在本地缓存,如果是这样,就不需要再建立网络连接)。如果DNS服务器找不到这个地址,这个方法会抛出一个UnknownHostException异常,这是IOException的一个子类。

  • static InetAddress[] getAllByName(String host)
    给定主机的名称,根据系统上配置的名称服务返回其IP地址数组,它会返回一个数组。

  • public static InetAddress getByAddress(byte[] addr)
    给出原始IP地址的InetAddress对象。参数是网络字节顺序:地址的最高位字节在getAddress()[0] 。 该方法不阻止,即不执行反向名称服务查找。返回从原始IP地址创建的InetAddress对象。

  • static InetAddress getLocalHost()
    返回本地主机的地址。

下面我们通过一段测试代码来演示以上的创建实例的办法:

public class TestInetAddress {
    public static void main(String[] args) throws Exception {
        System.out.println("-----getByName-----");
        InetAddress inet1 = InetAddress.getByName("www.baidu.com");
        System.out.println(inet1);

        System.out.println("-----getByName-----");
        InetAddress[] inet2 = InetAddress.getAllByName("www.baidu.com");
        System.out.println(inet2[0] + "/" + inet2[1]);

        System.out.println("-----getByAddress-----");
        byte[] b = new byte[]{(byte)220,(byte)181,1,102};
        InetAddress inet3 = InetAddress.getByAddress(b);
        System.out.println(inet3);

        System.out.println("-----getLocalHost-----");
        InetAddress inet4 = InetAddress.getLocalHost();
        System.out.println(inet4);
        System.out.println(inet4.getHostAddress());
        System.out.println(inet4.getHostName());
    }
}

输出:

-----getByName-----
www.baidu.com/220.181.111.188
-----getByName-----
www.baidu.com/220.181.111.188/www.baidu.com/220.181.112.244
-----getByAddress-----
/220.181.1.102
-----getLocalHost-----
japson-PC/192.168.1.102
192.168.1.102
japson-PC
方法摘要
  • public String getHostName()
    获取此ip地址的主机名,根据创建InetAddress对象的不同方式,getHostName的返回值是不同的。

  • public String getHostAddress()
    返回IP地址字符串。

  • public static InetAddress getLocalHost()
    返回本地主机

  • public booliean isReachable(int timeour)
    测试是否可以达到该地址

  • String getCanonicalHostName()
    获取此ip地址的完全限定域名

端口号

端口号标识正在本地计算机上运行的进程(程序)。不同的进程有不同的端口号。

端口号长度为16bit,能够表示0~65535。端口号只具有本地意义,不同计算机的相同端口号没有联系。根据端口号范围可将端口分为两类:

  1. 服务端使用的端口号:这里又分为两类:,0~1023为熟知端口号,被预先定义的服务通信占用(如MySql占用端口3306,http占用端口80等);1024~49151为登记端口号

  2. 客户端使用的端口号,数值为49152~65535,由于这类端口号仅在客户运行时才动态选择,因此右脚临时端口号。通信结束后,刚才使用过的客户端口号就不存在了。

套接字Socket

由上面我们已经知道了:在网络中通过IP地址来表示和区别不同的主机,通过端口号来标识和区分一台主机中的不同进程。

那么我们可以将二者融为一体,这就是套接字,套接字实际上一个通信端点。

在网络中采用发送方和接收方的套接字(Socket)组合来识别端点:

套接字 = (主机IP地址,端口号)

它唯一地表示了网络中的一个主机和其上的一个应用(进程)。网络通信其实就是Socket间的通信。通信的两端都要有Socket,是两台机器间通信的端点。

Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。一般主动发起通信的应用程序属客户端,等待通信请求的为服务端。

网络通信协议

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

通信协议分层的思想:

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

协议概述

我们使用TCP/IP协议族,其中有两个传输协议:

  • 面向连接的传输控制协议TCP:全双工的可靠的逻辑信道
  • 无连接的用户数据报协议UDP:不可靠的逻辑信道

TCP提供面向连接的服务,即在传送数据前必须先建立连接,数据传输结束后要释放连接。适用于可靠性更重要的场合,如:文件传输协议FTP,超文本传输协议HTTP、远程登录TELNET等。

UDP是一个无连接的非可靠的用户数据报协议,在传输数据前不需要建立连接,远程主机的传输层收到UDP报文后不需要给出确认。适用于速度快,实时性好的场景,如SNS,SNMP,RTP等。

UDP详解

UDP只做了传输协议能做到的最少的工作,只在IP的数据服务包上增加了复用和分用以及差错检测。使用UDP,程序几乎就是直接和ip打交道。

在某些情况下我们首选UDP,UDP有如下的有优点:

  • UDP无需建立连接。因此UDP不会引入建立连接的时延,会比较快。
  • 无连接状态。不维护连接船台,也不跟踪参数。
  • 分组首部开销小
  • 能更好的控制要奉送的数据和发送时间,稳定速度,容忍丢失,不允许较大时延

UDP首部

UDP数据报包含两部分:UDP首部和用户数据,整个UDP数据报作为IP数据报的数据部分封装子啊IP数据报中。UDP首部有8个字节,由4个字段组成:
1. 源端口:源端口号,在需要对方回信时选用,不需要时可用全0;
2. 目的端口:目的端口号,在终点交付报文时必须用到;
3. 长度:UDP数据报的长度,最小值为8;
4. 校验和:检测UDP数据报在传输中是否有错;

TCP协议详解

TCP协议的特点

TCP是在不可靠的ip层之上实现的可靠的数据传输协议,主要解决传输的可靠、有序。无丢失和不重复的问题。其特点有:

  1. TCP是面向连接的传输协议
  2. 每条TCP连接只能有两个端点,每条TCP连接只能是点对点(一对一)
  3. TCP提供可靠的交付服务,保证传送的数据无差错,不丢失,不重复且有序
  4. TCP提供全双工通信,允许双方的应用进程在任何时候都能发送数据
  5. TCP是面向字节流的,将数据看成 一连串的无结构的字节流

TCP报文段

TCP传送的数据单元称为报文段。一个TCP报文段分为TCP首部和TCP数据两部分,首部的前20字节是固定的。

TCP报文段既可以用来运载数据,也可以用来建立连接、释放连接和应答。
各字段意义如下:

  1. 源端口和目的端口(Source Port):16位的源端口字段包含初始化通信的端口号。源端口和IP地址的作用是标识报文的返回地址。

  2. 目的端口(Destination Port): 16位的目的端口字段定义传输的目的。这个端口指明接收方计算机上的应用程序接。

  3. 序列号字段(seq字段): TCP是面向字节流的,该字段用来标识TCP源端设备向目的端设备发送的字节流,它表示在这个报文段中所发送的数据的第一个字节的序号。序列号是一个32位的数。
    例如:以报文段的序号字段值是301,,而携带的数据共100个字节,这就表明本报文段的数据的最后一个字节的序号是400,故下一个报文段的数据序号应从401开始。

  4. 确认号字段(ack字段): TCP使用32位的确认号字段标识期望收到的下一个段的第一个字节,并声明此前的所有数据已经正确无误地收到,因此若确认号=N,则表明到学历噩耗N-1为止的所有数据都已经正确收到。确认号的字段只在ACK标志被设置时才有效。
    B:B正确的收到了A发送的一个报文段。其序号字段为501,数据长度200字节,则B期望收到A的下一个报文段的序号字段为701,于是B给A发送的确认报文段把确认号置为701。

  5. 数据偏移(Data Offset):这个4位字段包括TCP头大小。由于首部可能含有选项内容,因此TCP首部的长度是不确定的。首部长度的单位是32比特或4个八位组。首部长度实际上也指示了数据区在报文段中的起始偏移值。

  6. 保留(Reserved):6位置0的字段。为将来定义新的用途保留。

  7. 紧急位URG:当URG=1时,表示TCP包的紧急指针字段有效,用来保证TCP连接不被中断,并且督促中间齐备尽快处理这些紧急数据(优先级高)。

  8. 确认位ACK:只有ACK=1时确认字段有效,也即TCP应答号将包含在TCP段中,为0则确认号无效。TCP规定,在连接建立后所有传送的报文段都必须把ACK置为1。

  9. 推送位PSH:这个标志表示Push操作。接收TCP收到PSH=1的报文段后,立即送给应用程序,而不是在缓冲区中等到整个缓存都填满了再向上交付。

  10. 复位位RST:当RST=1时表明TCP连接中出现严重的差错,必须释放连接,然后再重新建立运输连接。

  11. 同步位SYN:同步SYN=1表示这是一个连接请求或连接接收报文。当SYN=1,ACL=0时,表明这是一个连接请求报文,对方若统一建立连接,则在响应报文中使用SYN=1,ACK=1。即SYN=1就表示这是一个连接请求或连接接收报文。

  12. 终止位FIN:FIN=1,表示发送端已经发送到数据末尾,数据传送完成,发送FIN标志位的TCP段,连接将被断开。

  13. 窗口字段(Window):目的主机使用16位的窗口字段告诉源主机它期望每次收到的数据通的字节数,即现在允许对方发送的数据量。

  14. 校验和(Checksum):TCP头包括16位的校验和字段用于错误检查。源主机基于部分IP头信息,TCP头和数据内容计算一个校验和,目的主机也要进行相同的计算,如果收到的内容没有错误过,两个计算应该完全一样,从而证明数据的有效性。

  15. 紧急指针字段(Urgent Pointer):紧急指针字段是一个可选的16位指针,指向段内的最后一个字节位置,这个字段只在URG标志被设置时才有效。

  16. 选项字段(Option):至少1字节的可变长字段,标识哪个选项(如果有的话)有效。如果没有选项,这个字节等于0,说明选项的结束。这个字节等于1表示无需再有操作;等于2表示下四个字节包括源机器的最大长度(Maximum Segment Size,MSS).

  17. 填充字段(Padding):这个字段中加入额外的零,以保证TCP头是32的整数倍。

TCP连接管理

TCP是面向连接的协议。因此每一个TCP连接都有三个阶段:连接建立、数据传送和连接释放。TCP连接的管理就是使运输连接的建立和释放都能正常运行。

在TCP连接建立的过程中要解决以下三个问题:
1. 要使每一方都能够确知对方的存在。
2. 要允许双方协商一些参数(如窗口大小值,时间戳选项以及服务质量等)。
3. 能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配。

TCP把连接作为最基本的抽象,每一条TCP连接有两个端点,TCP连接的端点就是套接字(Socket)。

每一条TCP连接唯一地被通信两端的两个Socket所确定。

TCP连接的建立采用客户/服务器方式。主动发起连接建立的应用进程叫做客户机(Client),而被动等待建立连接的应用进程叫做服务器(Server)。

TCP连接的建立(三次握手)

连接的建立需要经历一下三个步骤,通常称之为“三次握手”,如图所示:

三次握手

  • 第一步:
    客户机的TCP首先要向服务器的TCP发送一个连接请求报文段。这个特殊的报文段是一个SYN包,不含应用层数据。其首部中的SYN标志位被置为1。另外,客户机会随机选择一个起始序号(本报文所发送的数据的第一个字节的序号)seq=x(其实不含数据,但是也得占一位序列号)。此时客户端进入SYN_SEND状态,等待服务器确认。

客户端给服务器发信息:“首先声明这是一条请求消息,请问约么?”

  • 第二步:

服务器的TCP收到连接请求报文后,如统一建立连接,就向客户机发回确认(SYN+ACK包),并为该TCP连接分配TCP缓存的变量。在确认报文段中,SYN和ACK位都被置为1,ack(确认号字段)的值为期望收到的下一个报文段的数据的第一个字节的序列号,即已经收到x,期望下次收到 ack = x+1,并且服务器随机产生起始序号(本报文所发送的数据的第一个字节的序号)seq=y(其实不含数据,但是也得占一位序列号)。

服务器给客户机发信息:“我已收到你的消息,约!”

  • 第三步:
    当客户机收到服务器的返回的确认报文段(SYN+ACK包)后,还要向服务器给出确认包(ACK(ack=y+1)),并且也要给该连接分配缓存和变量。这个报文段的ACK被置为1,序号为 x+1,确认字段号为ack=y+1。之后客户端和服务器进入ESTABLISHED状态,完成三次握手。

客户机给服务器发信息:“OK!走起(发数据)。。。”

在成功的进行了以上三步之后,TCP连接就建立了,接下来就可以传送应用层数据了。TCP提供的是全双工通信,因此通信双方的应用进程在任何时候都能发送数据。

TCP连接的释放(四次挥手)

参与TCP连接的两个进程中的任何一个都能终止该连接。TCP连接释放的过程通常成为“四次挥手”:

四次挥手

  • 第一步:
    客户机打算关闭连接,就向其TCP发送一个连接释放报文段,并停止再发送数据,主动关闭TCP连接,该报文段的FIN标志被置为1,seq=u,seq等于前面已传送过的数据的最后一个字节的序号+1(FIN报文段即使不携带数据,也要消耗一个序号)。

客户机告诉服务器:“我已经不 会再给你发数据了!”(当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,客户机依然会重发这些数据),但是,此时客户机还可以接受数据。

  • 第二步:
    服务器接收到连接释放报文字段后即发出确认,确认号是ack=u+1,而这个报文段自己的序号是v,等于它前面已传送过的数据的最后一个字节的序号+1.此时客户机到服务器这个方向的连接就释放了,TCP处于半关闭状态。但服务器若要发送数据,客户机仍要接受,即从服务器到客户机这个方向的连接尚未关闭。
    这一步可以说是,服务器说:好,我知道你以后不再给我数据了。

  • 第三步:
    若服务器已经没有要向客户机发送的数据,就通知TCP释放连接,此时发出FIN=1的连接释放报文段。

服务器告诉客户机:我的数据也发送完了,不会再给你发数据了。

  • 第四步:
    客户机收到连接释放报文后,必须发出确认,ACK字段被置为1,确认号ack=w+1,序号seq=u+1。此时TCP连接还没有释放掉,必须等待时间2MSL后,客户机才进入到连接关闭状态。至此,完成四次挥手。

客户机告诉服务器:OVER(不用回了)。

总结

三次握手:

  1. 客户端发送SYN请求,进入SYN_SEND状态
  2. 服务端收到SYN请求,并返回一个ACK应答,并发送一个SYN其请求,服务器进入SYN_RECV状态
  3. 客户端收到服务端的SYN请求和ACK应答,发送ACK应答,客户端进入ESTABLISH状态,服务端收到应答后进入ESTABLISH。
    如果没有收到应答,数据包都会根据TCP的重传机制进行重传。

四次挥手:

  1. 客户端发送FIN包,请求断开连接,客户端进入FIN_WAIT1状态
  2. 服务端收到FIN包后返回应答,进入CLOSE_WAIT状态
  3. 客户端收到FIN的应答后进入FIN_WAIT2状态
  4. 服务端发送FIN请求包,进入LAST_ACK状态
  5. 客户端收到FIN请求包后,发送应答进入TIME_WAIT状态
  6. 服务器收到ACK应答后,进入close状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值