• 学习笔记11


    本章论述了 TCP/IP和网络编程,分为两个部分。第一部分论述了 TCP/IP协议及其应 用,具体包括TCP/IP栈、IP地址、主机名、DNSIP数据包和路由器;介绍了 TCP/IP 络中的UDPTCP协议、端口号和数据流;阐述了服务器-客户机计算模型和套接字编程 接口;通过使用UDPTCP套接字的示例演示了网络编程。第一个编程项目可实现一对通 过互联网执行文件操作的TCP服务器-客户机,可让用户定义其他通信协议来可靠地传输 文件内容。本章的第二部分介绍了 WebCGI编程,解释了 HTTP编程模型、Web页面和Web 览器;展示了如何配置Linux HTTPD服务器来支持用户Web页面、PHPCG1编程;阐 释了客户机和服务器端动态Web页面;演示了如何使用PHPCGI创建服务器端动态Web 页面。第二个编程项目可让读者在Linux HTTPD服务器上通过CGI编程实现服务器端动态 Web页面。

    思维导图

    知识点归纳

    网络编程简介

    如今,上网已成为日常生活的需要。虽然大多数人可能只把互联网作为一种信息收集、 网上购物和社交媒体等的工具,但计算机科学的学生必须对互联网技术有一定的了解,并掌 握一定的网络编程的技能。在本章中,我们将介绍TCP/IP网络和网络编程的基础知识,包 括TCP/IP协议、UDPTCP协议、服务器-客户机计算、HTTPWeb页面、动态Web 页面的PHPCGI编程。

    TCP/IP 协议

    TCP/IP (Comer 1988, 2001; RFC1180 1991 )是互联网的基础。TCP代表传输控制协议。 IP代表互联网协议。目前有两个版本的IP,IPv4IPv6o IPv4使用32位地址,IPv6 使用128位地址。本节围绕IPv4进行讨论,它仍然是目前使用最多的IP版本。TCP/IP 组织结构分为几个层级,通常称为TCP/IP堆栈,图13.1所示为TCP/IP的各个层级以及每 一层级的代表性组件及其功能。

    Layer

    -Components -

    Functions

    | Application Layer

    I ssh ping

    | Application commands

    | Transport Layer

    | TCP UCP

    | Connection Datagram

    | Internet Layer

    1 IP

    | send/receive data frames |

    | Link Layer

    Ethernet

    | send/receive data frames |

     

    顶层是使用TCP/IP的应用程序。用于登录到远程主机的ssh用于交换电子邮件的mail用于Web页面的http等应用程序需要可靠的数据传输。通常,这类应用程序在传输 层使用TCP另一方面,有些应用程序,例如用于查询其他主机的ping命令,则不需要可 靠性。这类应用程序可以在传输层使用UDP来提高效率(RFC 768 1980; Comer 1988 )。传 输层负责以包的形式向IP主机发送/接收来自IP主机的应用程序数据。进程与主机之间的 传输层或其上方的数据传输只是逻辑传输。实际数据传输发生在互联网(【P)和链路层,这 些层将数据包分成数据帧,以便在物理网络之间传输。

    IP主机和IP地址

    主机是支持TCP/IP协议的计算机或设备。每个主机由一个32位的IP地址来标识。为 了方便起见,32位的IP地址号通常用点记法表示,例如:134.121.64.1,其中各个字节用点 号分开。主机也可以用主机名来表示,如dnsl.eec.wsu.edu实际上,应用程序通常使用主 机名而不是IP地址。在这个意义上说,主机名就等同于IP地址,因为给定其中一个,我们 可以通过DNS (域名系统)(RFC 134 1987; RFC 1035 1987 )服务器找到另一个,它将IP 址转换为主机名,反之亦然。

    IP地址分为两部分,即NetworkID字段和HostID字段。根据划分,1P地址分为A~E 类。例如,一个BJP地址被划分为一个16NetworklD,其中前2位是10,然后是一 个16位的HostID字段。发往IP地址的数据包首先被发送到具有相同networklD的路由器。 路由器将通过HostID将数据包转发到网络中的特定主机。每个主机都有一个本地主机名 localhost,默认IP地址为127.0.0.1。本地主机的链路层是一个回送虚拟设备,它将每个数 据包路由回同一个localhost0这个特性可以让我们在同一台计算机上运行TCP/IP应用程序, 而不需要实际连接到互联网。

    IP协议

    ip协议用于在ip主机之间发送/接收数据包。ip尽最大努力运行。】p主机只向接收主 机发送数据包,但它不能保证数据包会被发送到它们的目的地,也不能保证按顺序发送。这 意味着ip并非可靠的协议。必要时,必须在ip层的上面实现可靠性。

    IP数据包格式

    ip数据包由ip头、发送方ip地址和接收方ip地址以及数据组成。每个ip数据包的大 小最大为64KB1P头包含有关数据包的更多信息,例如数据包的总长度、数据包使用TCP 还是UDP生存时间TTL)计数、错误检测的校验和等。图

     路由器

    ip主机之间可能相距很远。通常不可能从一个主机直接向另一个主机发送数据包。路 由器是接收和转发数据包的特殊ip主机。如果有的话, 一个ip数据包可能会经过许多路由器,或者跳跃到达 某个目的地。图13.4显示了 TCP/IP网络的拓扑结构。

    每个IP包在1P报头中都有一个8位生存时间 TTL)计数,其最大值为255。在每个路由器上,TTL

    会减小1。如果TTL减小到0,而包仍然没有到达目的地,则会直接丢弃它。这可以防止任 何数据包在IP网络中无限循环。

     UDP

    UDP (用户数据报协议)RFC 768 1980; Comer 1988 )在IP上运行,用于发送/接收数 据报。与IP类似,UDP不能保证可靠性,但是快速高效.它可用于可靠性不重要的情况。 例如,用户可以使用ping命令探测目标主机,如

    ping主机名或ping IP地址

    ping是一个向目标主机发送带时间戳UDP包的应用程序。接收到一个pinging数据包 后,目标主机将带有时间戳的UDP包回送给发送者,让发送者可以计算和显示往返时间。 如果目标主机不存在或宕机,当TTL减小为0时,路由器将会丢弃pinging UDP数据包。 在这种情况下,用户会发现目标主机没有任何响应。用户可以尝试再次ping,或者断定目标 主机宕机。在这种情况下,最好使用UDP,因为不要求可靠性。

     TCP

    TCP (传输控制协议)是一种面向连接的协议,用于发送/接收数据流。TCP也可在IP 上运行,但它保证了可靠的数据传输。通常,UDP类似于发送邮件的USPS,TCP类似 于电话连接。

    端口编号

    在各主机上,多个应用程序(进程)可同时使用TCP/UDP.每个应用程序由三个组成
    部分唯一标识

    应用程序=(主机IP,协议,端口号)

    其中,协议是TCPUDP,端口号是分配给应用程序的唯一无符号短整数。要想使用 UDPTCP,应用程序(进程)必须先选择或获取一个端口号。前1024个端口号已被预留。 其他端口号可供一般使用。应用程序可以选择一个可用端口号,也可以让操作系统内核分配 端口号。图13.5给出了在传输层中使用TCP的一些应用程序及其默认端口号。

     网络和主机字节序

    计算机可以使用大端字节序,也可以使用小端字节序。在互联网上,数据始终按网络 序排列,这是大端。在小端机器上,例如基于Intel x86PC, htons。、htonl。、ntohs() ntohl等库函数,可在主机序和网络序之间转换数据。例如,PC中的端口号1234按主机字 节序(小端)是无符号短整数。必须先通过htons(1234)把它转换成网络序,才能使用。相 反,从互联网收到的端口号必须先通过ntohs(port)转换为主机序。

    网络编程

    所有Unix/Linux系统都为网络编程提供TCP/IP支持。本节,我们将会阐释用于网络编 程的平台和服务器-客户机计算模型。

    网络编程平台

    要进行网络编程,读者必须能够访问支持网络编程的平台。可通过下面几种方法访问这 类平台。

    (1 )服务器上的用户账户:现在,几乎所有的教育机构都为它们的教职工和学生提供了 网络接入,通常是以无线连接的形式。每位机构成员都要能够登录服务器以接入互联网、服 务器是否允许一般的网络编程取决于本地网络管理策略。这里,我们要介绍作者所在机构 (华盛顿州立大学电气工程与计算机科学系)的网络编程平台的设置。作者有一个专用服 务器
    
    cs360.eecs.wsu.edu
    
    服务器运行14.2版Slackware Linux,完全支持网络编程。这台服务器在华盛顿州立大学电 气工程与计算机科学系的DNS服务器上注册。当服务器启动时,它会使用DHCP (动态主 机配置协议)从DHCP服务器上获取一个私有IP地址(RFC 2131 1997 )o虽然它不是公共 IP地址,但可以通过NAT (网络地址转换)在互联网上访问它:然后,作者为CS360班级 的学生创建用户账户,供他们登录。学生大多通过WSU无线网络将笔记本电脑连接到互联 网上。一旦连上互联网,他们就可以登录CS360服务器了e
    
    (2)单独PC或笔记本电脑:即便学生未接入服务器.仍然可以使用计算机的本地主 机在单独计算机上进行网络编程。在这种情况下,学生需要下載安装一些网络部件。例如, Ubuntu Linux用户可能需要安装和配置用于HTTP和CGI编程的Apache服务器,这将在后 面的13.17节中讨论。

    服务器-客户机计算模型

    大多数网络编程任务都基于服务器-客户机计算模型。在服务器-客户机计算模财中. 我们首先在服务器主机上运行服务器进程。然后,我们从客户机主机运行客户机在UDP 中,服务器等待来自客户机的数据报,处理数据报并生成对客户机的响应。在TCP中,服 务器等待客户机连接。客户机首先连接到服务器,在客户机和服务器之间建立一个虚拟电 路,建立连接后,服务器和客户机可以交换连续的数据流:下面,我们将展示如何使用 UDPTCP进行网络编程。

    套接字编程

    在网络编程中,TCP/IP的用户界面是通过一系列C语言库函数和系统调用来实现的, 这些函数和系统调用统称为套接字API (( Rago 1993; Stevens2004 )。为了使用套接宇 API,我们需要套接字地址结构,它用于标识服务器和客户机。netdb.hsys/socket.h中有 套接字地址结构的定义。

    套接字地址在套接字地址结构中,

        TCP/IP 网络的 sin_family 始终设置为 AF_INET。
        sm_port包含按网络字节顺序排列的端口号。
        sin_addr是按网络字节顺序排列的主机IP地址。

     套接字 API

    服务器必须创建一个套接字,并将其与包含服务器IP地址和端口号的套接字地址绑 定。它可以使用一个固定端口号,或者让操作系统内核选择一个端口号(如果sin_port 0)o为了与服务器通信,客户机必须创建〜个套接字。对于UPD套接字,可以将套接字绑 定到服务器地址。如果套接字没有绑定到任何特定的服务器,那么它必须在后续的sendto()/ recvfromO调用中提供一个包含服务器IP和端口号的套接字地址。下面给出了 socket系统 调用,它创建一个套接字并返回一个文件描述符

    Lint套接字(int域,int类型,int协议)

    示例:

    int udp_sock = socket(AF_INET, SOCK_DGRAM, 0);
    

     将会创建一个用于发送/接收UDP数据报的套接字。

    int udp_sock = socket(AF_INET, SOCK_DGRAM, 0);

    int udp_sock = socket(AF_INET, SOCK_DGRAM, 0);

    将会创建一个用于发送/接收数据流的面向连接的TCP套接字c

    新创建的套接字没有任何相联地址c它必须与主机地址和端口号绑定,以识别接收主机 或发送主机:这通过bind系统调用来完成,

    1. UDP套接字

    UDP套接字使用scndto()/recvfrom()来发送/接收数据报。

    aendto(int aockfdr const void *bufr size.t len, lot flags,
    
    const struct sockaddr •de8t_addrf socklen_t addrlen)|
    
    asize_t recvfrora(int sock£d, void *buf, aiza_t len, int flags, struct sockaddr *Btc_addr, aocklen_t *addrlen};
    
    sendto()将缓冲区中的len字节数据发送到由dest_addr标识的目标主机,该目标主机包 含目标主机P和端口号。recvfrom()从客户机主机接收数据。除了数据之外,它还用客户机 的IP和端口号填充src_addr,从而允许服务器将应答发送回客户机:
    1. TCP套接字

    在创建套接字并将其绑定到服务器地址之后,TCP服务器使用listen()acccpt()来接 收来自客户机的连接

    int Iistcn(int sockfd, int backlog);

     listen()sockfd引用的套接字标记为将用于接收连入连接的套接字。backlog参数定义了等 待连接的最大队列长度。

    int accept(int sockfd, struct sockaddr *addr, sockien_t *addrlen);

     accept()系统调用与基于连接的套接字一起使用。它提取等待连接队列上的第一个连接请求 用于监听套接字sockfd,创建一个新的连接套接字,并返回一个引用该套接字的新文件描 述符,与客户机主机连接。在执行accept()系统调用时,TCP服务器阻塞,直到客户机通过 coimectO建立连接。

     

    int connect(int sockfd, const struct sockaddr *addr, socklen t addrlen);

    connect()系统调用将文件描述符sockfd引用的套接字连接到addr指定的地址,addrlen参数 指定addr的大小。addr中的地址格式由套接字sockfd的地址空间决定。

    如果套接字sockfdSOCK_DGRAM类型,即UDP套接字,addr是发送数据报的默 认地址,也是接收数据报的唯一地址。这会限制UDP套接字与特定UDP主机的通信,但 实际上很少使用。所以对于UDP套接字来说,连接是可选的或不必要的。如果套接字是 SOCK_STREAM类型,即TCP套接字,connect()调用尝试连接到绑定到addr指定地址的 套接字C

    1. send()/read()以及 recv/write()

    建立连接后,两个TCP主机都可以使用send()/write()发送数据,并使用recv()/read 接收数据。它们唯一的区别是sendrecv()中的nag参数不同,通常情况下可以将其设 置为0

    ssize_t send(int Bockfd, const void *bufr size.t len« int flags);
    
    write(sockfd/ void *buf, aize_t, l«n)
    
    S0izo_t recv(int sockfd, void *buf# size_t len, int flags);
    
    ssize_t read(sockfd, void *buf, size_t len)j
     Web 页面

    Web页面是用HTML标记语言编写的文件。Web文件通过一系列HTML元素指定 Web页面的布局,可在Web浏览器上解释和显示。常用的Web浏览器有Internet Explorer, FirefoxGoogle Chrome等。创建Web页面相当于使用HTML元素作为构建块创建文本文 件。与其说它是编程,不如说是文书类工作。因此,我们不讨论如何创建Web页面。相反, 我们将只使用一个示例HTML文件来说明Web页面的本质。下面给出了 •个简单的HTML Web文件。HTML文件内容说明

    HTML文件包含多个HTML元素。每个HTML元素由一对匹配的打开和关闭标记 指定。

    <tag>contents</tag>

    实际上,HTML文件本身可以看作是由一对匹配的<html>标记指定的HTML元素。

    <html>HTML file</html>

    书中第126行指定了一个HTML文件。一个HTML文件包含一个由一对匹配的<body>标记 指定的主体

    <body>body of HTML file</body>

    225行指定了 HTML文件的主体。

    HTML文件可以使用标签<H1><H7>来显示不同字体大小的标题行。

    3行指定了一个标题行。

    每对匹配的<P>标记指定一个段落,该段落显示在新行中。

    4行指定了一段文本。

    5行指定了一个注释行,浏览器将会忽略它。

    6行指定了一个图像文件,它将按每行的宽度像素显示。

    7行指定了一个链接元素

    <a HREF=wlink_URLM>link</a>

    其中,属性HREF指定一个link_URL和一个描述链接的文本字符串。浏览器通常以深 蓝色显示链接文本。如果用户单击链接,它将把请求定向到由link_URL标识的Web 务器。这可能是Web页面最强大的特性。它允许用户通过跟随链接导航到Web中的任何 地方。

    8行至第10行使用<font>元素来显示不同颜色的文本。<font>元素还可以指定不同
    字体大小和样式的文本。

    11行至第20行指定一个表,tr>为行,th> 为各行中的列。

    2124行指定了一个表单,用于收集用户输 入并将其提交给Web服务器进行处理。我们将在下一 节的CGI编程中更详细地解释和演示HTML表单。

    php

    下面显示了一个简单的PHP文件pl .php

    <html>
    
    <body>
    
    <?php
    
    •cho XAhello world<br>w; // hello world<br> print ''see you later<br>**/// see you later<br>
    
    ?>
    
    </body>
    
    C程序类似,每个PHP语句的末尾都必须使用分号。它可以在匹配的/**/对 中包含注释块,或者单个注释行使用〃和#。对于输出,PHP可以使用echoprinte echoprint语句中,多个项必须用点(字符串连接)运算符分开,而不是用空格分 开,如
    echo ''hello world<br> . ''see you later<br>w;
    

     Web客户机请求pl.php文件时,httpd服务器的PHP预处理器将先执行PHP语句来 生成HTML(显示在PHP行右侧),然后将生成的HTML文件发送到客户机。

    (2 ) PHP变量:在PHP中,变量以$符号开头,其后是变量名。PHP变量值可以是字 符串、整数或浮点数。与C语言不同,PHP是一种松散类型的语言。用户不需要使用类型 定义变量。与C语言一样,PHP也允许类型转换更改变量类型。对于大多数情况,PHP 可以自动将变量转换为不同的类型。

     
    
    echo «$STR Sum=$C<br>w; // hello world! Sxima579<br>

    C语言或sh脚本中的变量一样,PHP变量可以是局部变量、全局变量或静态 变量。

    (3) PHP运算符:在PHP中,变量和值可以由以下运算符操作。

    ・算术运算符
    
    ・赋值运算符
    
    •比较运算符
    
    •递增/递减运算符
    
    -逻辑运算符
    
    ・字符串运算符
    
    ・数组运算符
    大多数PHP运算符类似于C语言中的运算符。我们只在PHP中显示一些特殊的字符串 和数组运算符。

    (3) .1字符串运算:大多数字符串运算,如strlen()strcmp()等,与C语言相同。PHP 还支持许多其他字符串运算,它们的语法形式通常略有不同。例如,PHP不使用strcat(), 而是使用点运算符进行字符申连接,如*• string 1 string?" 0

    (3) .2 PHP数组:PHP数组用array()关键字定义。PHP支持索引数组和多维数组。可 通过数组索引单步遍历索引数组,如此外,PHP数组可由运算符进行集合运算,如并集(+)和比较,也可进行列表运算, 可按不同的顺序排列。

    关联数组:关联数组由名称-值对组成。

    $A ■ array('name*=>l, *namel*=>2, *name2*=>3z wname*=>4);
    

    关联数组允许按名称而不是索引访问元素值,如

    echo wvalue of namel ■ * . $A[ Xnaxnel * ] /
    

    (4 ) PHP 条件语句:PHP 通过 ififelseif-elseif-else switch-case 语句支持条件和

    测试条件,这些语句与C语言中的语句全相同,但语法上略有不同。

     实践练习

    代码:

     码云链接:https://gitee.com/tin_ting/ch13./blob/master/ch13

     遇到的问题和解决

    遇到的问题:套接字系统调用和对应包裹函数有哪些?

    解决:通过查询csdn以及博客园和知乎等平台,归纳如下知识点:

    socket
    int Socket (int __domain, int __type, int __protocol)
    {
        int socketfd;
        if((socketfd = socket(__domain , __type , __protocol)) < 0)
            err_quit("socket error");
        return socketfd;
    }
    
    bind
    int Bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)
    {
        int rc;
        if((rc = bind(__fd , __addr , __len)) < 0)
            err_quit("bind error");
        return (rc);
    }
    
    accept
    int Accept (int __fd, __SOCKADDR_ARG __addr , socklen_t *__restrict __addr_len)
    {
         int fd;
         if((fd = accept(__fd , __addr , __addr_len)) < 0)
             err_quit("accept err");
         return (fd);
    }
    
    listen
    int Listen (int __fd, int __n)
    {
        int rc;
        if((rc = listen(__fd , __n)) < 0)
            err_quit("listen err %d" , __fd);
        return (rc);
    }
    


     

  • 相关阅读:
    解锁 redis 锁的正确姿势
    PHP实现Redis单据锁,防止并发重复写入
    js笔记
    FormData使用方法详解
    jquery里用each遍历的值存到数组和字符串
    Sublime Text3 安装 CTags 插件出现乱码
    通过pd.to_sql()将DataFrame写入Mysql
    ERROR 2002 (HY000): Can't connect to local MySQL server through socket
    pandas 从txt读取DataFrame&DataFrame格式化保存到txt
    pandas 取消读取csv时默认第一行为列名
  • 原文地址:https://www.cnblogs.com/stx3220665294/p/15616631.html
Copyright © 2020-2023  润新知