Fork me on GitHub

网络编程


网络编程

Linux下常用的进程间通信,如管道,FIFO,消息队列,信号量和共享内存等,他们的应用局限于单一计算机内的进程通信;而基于套接口的方式不仅可以实现单机内的进程间通信,还可以实现不同计算机进程之间的通信。

网络编程的基础知识

  1. 为了能够使分布在不同地理且功能相对独立的计算机之间组成网络实现资源共享,计算机网络系统需要设计和解决许多复杂的问题,包括信号传输,差错控制,寻址,数据交换和提供用户接口等一系列问题。

    计算机网络体系结构就是为了简化这些问题的研究,设计与实现而抽象出来的一种结构模型。这种结构模型,一般采用层次模型。在层次模型中,往往将系统所要实现的复杂功能分化为若干个相对简单的细小功能,每一项分功能以相对独立的方式去实现。

  2. OSI七层模型

    OSI描述了网络硬件和软件如何以层的方式协同工作进行网络通信

    • 物理层

      • 物理层并不是指物理设备或物理媒体,而是有关物理设备通过物理媒体进行互连的描述和规定。物理层协议定义了接口的机械特性,电气特性,功能特性,规程特性等4个基本特性。
      • 物理层以比特流的方式传送来自数据链路层的数据,而不去理会数据的含义和格式。同样,它接收数据后直接传给数据链路层。也就是说,物理层只能看见0和1,它没有一种机制用于确定自己所处理的比特流的具体意义,而只与数据通信的机械或电气特性有关。
    • 数据链路层

      负责通过物理层从一台计算机到另一台计算机无差错地传输数据帧,允许网络层通过网络连接进行虚拟无差错地传输

      • 通常,数据链路层发送一个数据帧后,等待接收方的确认。接收方数据链路层检测帧传送过程中产生的任何问题。没有进过确认的帧和损坏的帧都要进行重传。
    • 网络层

      负责信息寻址和将逻辑地址与名字转换为物理地址

      • 在网络层,数据传送的使IP数据包。网络层的任务就是要选择合适的路径和转发IP数据包,使发送方的数据包能够正确无误地按地址寻找到接收方的路径,并将数据包交给接收方。
      • 网络中两节点之间达到的路径可能有很多,应通过哪条路径才能将数据从原设备传送到所要通信的目的设备,在寻找最快捷,花费最低的路径时,必须考虑网络拥塞程度,服务质量,线路的花费和线路的有效性等诸多因素。总的来说,网络层负责选择最佳路径
      • 网络层处于传输层和数据链路层之间,它负责向传输层提供服务,同时负责将网络地址翻译成对应的物理地址。网络层还能协调发送,传输及接受设备的能力不平衡的问题,如网络层对数据进行分段和重组,以使得数据的长度能够满足该网络下层数据链路层所支持的最大的数据帧(MTU)的长度
      • 另外,网络层还需要考虑采用不同的网络层协议的网络之间的相互连接的问题,如TCP/IP使用的IP协议和NOVELL使用的IPX协议之间的相互连接
    • 传输层

      保证在不同子网的两台设备间数据包可靠,顺序,无错地传输。

      • 在传输层,数据传送的单位是段。传输层负责处理端对端通信,所谓端对端是指从一个终端(主机)到另一个终端(主机),中间可以有一个或多个交换节点。
      • 传输层向高层用户提供端对端的可靠的透明传输服务,为不同进程间的数据交换提供可靠的传送手段。在传输层一个很重要的工作是数据的分段和重组,即把上层数据分割成更小的逻辑片或物理片。换而言之,也就是发送方在传输层把上层交给它的较大的数据进行分段后分别交给网络层进行独立传输,从而实现在传输层的流量控制,提高网络资源的利用率。接收方将收到的分段的数据重组,还原成为原先完整的数据。
      • 另外,传输层的另一个主要功能就是将收到的乱序数据包重新排序,并验证所有的分组是否都已被收到
    • 会话层

      会话层是利用传输层提供的端到端的服务,向表示层或会话用户提供会话服务。会话层的主要功能是在两个节点间建立,维护和释放面向用户的连接,并对会话进行管理和控制,保证会话数据可靠传送。

    • 表示层

      • OSI模型中,表示层以下的各层主要负责数据在网络中传输时不出错。但数据的传输没有出错,并不代表数据所表示的信息就不会出错。表示层专门负责有关网络中计算机信息的表示方式的问题。表示层负责在不同的数据格式之间进行转换操作,以实现不同计算机系统间的信息交换。
      • 除了编码外,还包括数据,浮点数,记录,图像,声音等多种数据结构,表示层用抽象的方式来定义交换中使用的数据结构,并且在计算机内部表示法和网络的标准表示法之间进行转换。
      • 表示层还负责数据加密,以在数据的传输过程对其进行保护。数据在发送端被加密,在接收端解密。使用加密密钥来对数据进行加密和解密。
      • 表示层还负责文件的压缩,通过算法来压缩文件的大小,降低传输费用
    • 应用层

      负责对软件提供接口以使软件能使用网络。它不为任何其他OSI层提供服务,而只为OSI模型以外的应用程序提供服务,如电子表格程序和文字处理程序。

  3. TCP是面向连接的,UDP是无连接的,需要指出的是,TCP/IPOSI模型之前的产物,所以两者间不存在严格的层对应关系。其次,TCP采用具有重传功能的积极确认技术作为可靠数据流传输服务的基础。

套接口编程基础

套接口是操作系统内核中的一个数据结构,它是网络中的节点进行相互通信的门户。网络编程实际上也可以称为套接口编程。

  1. 什么是套接口

    套接口也就是网络进程的ID。网络通信归根到底还是进程间的通信(不同计算机上的进程间通信)。在一台计算机中,一个端口号一次只能分配给一个进程,也就是说,使用端口号和网络地址的组合就能唯一的确定整个网络中的一个网络进程

    提示:套接口在编程中,所有的函数与结构体均是小写字母,只有常量才是大写字母

  2. Socket网络层次

    1. 套接字的分类

      常用的TCP/IP协议的3种套接字类型如下所示。

      • 流套接字(SOCK_STREAM):

      流套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复发送,并按顺序接收。流套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即TCPThe Transmission Control Protocol)协议。

      • 数据报套接字(SOCK_DGRAM):

      数据报套接字提供了一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDPUser Datagram Protocol)协议进行数据的传输。由于数据报套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程序中做相应的处理。

      • 原始套接字(SOCK_RAW):

      原始套接字(SOCKET_RAW)允许对较低层次的协议直接访问,比如IPICMP协议,它常用于检验新的协议实现,或者访问现有服务中配置的新设备,因为RAW SOCKET可以自如地控制Windows下的多种协议,能够对网络底层的传输机制进行控制,所以可以应用原始套接字来操纵网络层和传输层应用。比如,我们可以通过RAW SOCKET来接收发向本机的ICMPIGMP协议包,或者接收TCP/IP栈不能够处理的IP包,也可以用来发送一些自定包头或自定协议的IP包。网络监听技术很大程度上依赖于SOCKET_RAW

      原始套接字与标准套接字(标准套接字指的是前面介绍的流套接字和数据包套接字)的区别在于:原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。因此,如果要访问其他协议发送数据必须使用原始套接字。

    2. 套接口的数据结构

      套接口的数据结构与使用它的网络有关。在Linux中,每一种协议都有自己的网络地址数据结构,这些结构以sockaddr_开头,不同的是后缀表示不同的协议,如IPv4对应的是sockaddr_in

      1. 通用套接口地址数据结构

        由于历史的缘故,在bind,connect等系统调用中,特定于协议的套接口地址结构指针都要强制转换成该通用的套接口地址结构指针,以实现协议的无关性。该结构被定义在<sys/socket.h>

        1
        2
        3
        4
        5
        6
        struct sockaddr
        {
        uint8_t sa_len;
        sa_family sa_family; /* address family,AF_xxx */
        char sa_data[14]; /* 14bytes of protocol address */
        };

        uint8_tPOSIX.1要求的数据类型。在后续中,将会经常看到这种数据类型,他们都以_t结尾。

      2. IPv4套接口地址数据结构

        IPv4套接字地址数据结构以socketaddr_in命名,定义在<netinet/in.h>

        1
        2
        3
        4
        5
        6
        7
        8
        struct socketaddr_in
        {
        uint8_t sin_len; /* 长度成员,无需设置 */
        sa_family_t sin_family; /* 套接口地址族,如IPv4为AF_INET */
        in_port_t sin_port; /* 16为TCP或UDP端口号,网络字节顺序 */
        struct in_addr sin_addr;
        unsigned char sin_zero[8]; /* 未用 */
        };

        结构体的成员in_addr也是一个结构体,定义如下所示

        1
        2
        3
        4
        struct in_addr
        {
        in_addr_t s_addr; /* 32位IPv4地址,网络字节顺序 */
        };

        在这些数据结构中,成员变量的作用与含义如下所示

        • sin_len:数据长度成员,固定长度为16字节,一般不要设置
        • sin_family:即为sa_family,为调用socket()时的family参数。IPv4协议族为AF_INET
        • sin_port:使用的端口号
        • sin_addr.s_addr:IP地址
        • sin_zero:未使用的字段,填充0。
数据类型 说明 定义所在的头文件
int8_t 带符号的8位整数 <sys/types.h>
uint8_t 无符号的8位整数 <sys/types.h>
int16_t 带符号的16位整数 <sys/types.h>
uint16_t 无符号的16位整数 <sys/types.h>
int32_t 带符号的32位整数 <sys/types.h>
uint32_t 无符号的32位整数 <sys/types.h>
sa_family_t 套接口地址结构的地址族 <sys/socket.h>
socklen_t 套接口地址结构的长度,一般为uint32_t <sys/socket.h>
in_port_t TCPUDP端口号,一般为uint16_t <netinet/in.h>
in_addr_t IPv4地址,一般为uint32_t <netinet/in.h>
坚持原创技术分享,您的支持将鼓励我继续创作
-------------本文结束感谢您的阅读-------------
0%