zoukankan      html  css  js  c++  java
  • 《Unix/Linux系统编程》第十三章学习笔记

    《Unix/Linux系统编程》第十三章学习笔记

    知识点总结

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

    TCP/IP协议

    • 从字面意义上讲,有人可能会认为 TCP/IP 是指 TCP 和 IP 两种协议。实际生活当中有时也确实就是指这两种协议。然而在很多情况下,它只是利用 IP 进行通信时所必须用到的协议群的统称。具体来说,IP 或 ICMP、TCP 或 UDP、TELNET 或 FTP、以及 HTTP 等都属于 TCP/IP 协议。他们与 TCP 或 IP 的关系紧密,是互联网必不可少的组成部分。TCP/IP 一词泛指这些协议,因此,有时也称 TCP/IP 为网际协议群。
    • 互联网进行通信时,需要相应的网络协议,TCP/IP 原本就是为使用互联网而开发制定的协议族。因此,互联网的协议就是 TCP/IP,TCP/IP 就是互联网的协议。

    IP主机和IP地址

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

    IP协议

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

    UDP/TCP

    UDP(用户数据报协议)(RFC768 1980;Comer 1988)在IP上运行,用于发送/接收数据报。与IP类似,UDP不能保证可靠性,但是快速高效。它可用于可靠性不重要的情况。

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

    端口编号

    应用程序 =(主机 IP,协议,端口号)
    其中,协议是TCP或 UDP,端口号是分配给应用程序的唯一无符号短整数。要想使用UDP或 TCP,应用程序(进程)必须先选择或获取一个端口号。前1024个端口号已被预留。其他端口号可供一般使用。应用程序可以选择一个可用端口号,也可以让操作系统内核分配端口号。

    套接字编程

    (1)套接字地址

    struct sockaddr_in {
    sa_family_t sin_family; // AF_INET for TCP/IP
    // port number
    in_port_t sin_port;
    struct in_addr sin_addr;// IP address );
    // internet address struct in_addr {
    // IP address in network byte order
    s_addr;
    uint32_t
    );
    

    (2)套接字API

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

    实践

    #include <stdio.h>
    #include <arpa/inet.h>//inet_addr() sockaddr_in
    #include <string.h>//bzero()
    #include <sys/socket.h>//socket
    #include <unistd.h>
    #include <stdlib.h>//exit()
    
    #define BUFFER_SIZE 1024
    
    int main() {
    
        char listen_addr_str[] = "0.0.0.0";
        size_t listen_addr = inet_addr(listen_addr_str);
        int port = 8080;
        int server_socket, client_socket;
        struct sockaddr_in server_addr, client_addr;
        socklen_t addr_size;
        char buffer[BUFFER_SIZE];//缓冲区大小
        int str_length;
        server_socket = socket(PF_INET, SOCK_STREAM, 0);//创建套接字
        bzero(&server_addr, sizeof(server_addr));//初始化
        server_addr.sin_family = INADDR_ANY;
        server_addr.sin_port = htons(port);
        server_addr.sin_addr.s_addr = listen_addr;
        if (bind(server_socket, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1) {
            printf("绑定失败\n");
    
            exit(1);
    
        }
    
        if (listen(server_socket, 5) == -1) {
    
            printf("监听失败\n");
    
            exit(1);
    
        }
    
        printf("创建tcp服务器成功\n");
    
     
    
     
    
        fd_set reads,copy_reads;
    
        int fd_max,fd_num;
    
        struct timeval timeout;
    
     
    
        FD_ZERO(&reads);//初始化清空socket集合
    
        FD_SET(server_socket,&reads);
    
        fd_max=server_socket;
    
     
    
     
    
        while (1) {
    
            copy_reads = reads;
    
            timeout.tv_sec = 5;
    
            timeout.tv_usec = 5000;
    
     
    
            //无限循环调用select 监视可读事件
    
            if((fd_num = select(fd_max+1, &copy_reads, 0, 0, &timeout)) == -1) {
    
                perror("select error");
    
                break;
    
            }
    
            if (fd_num==0){//没有变动的socket
    
                continue;
    
            }
    
     
    
            for(int i=0;i<fd_max+1;i++){
    
                if(FD_ISSET(i,&copy_reads)){
    
                    if (i==server_socket){//server_socket变动,代表有新客户端连接
    
                        addr_size = sizeof(client_addr);
    
                        client_socket = accept(server_socket, (struct sockaddr *) &client_addr, &addr_size);
    
                        printf("%d 连接成功\n", client_socket);
    
                        char msg[] = "恭喜你连接成功";
    
                        write(client_socket, msg, sizeof(msg));
    
                        FD_SET(client_socket,&reads);
    
                        if(fd_max < client_socket){
    
                            fd_max=client_socket;
    
                        }
    
                    }else{
    
                        memset(buffer, 0, sizeof(buffer));
    
                        str_length = read(i, buffer, BUFFER_SIZE);
    
                        if (str_length == 0)    //读取数据完毕关闭套接字
    
                        {
    
                            close(i);
    
                            printf("连接已经关闭: %d \n", i);
    
                            FD_CLR(i, &reads);//从reads中删除相关信息
    
                        } else {
    
                            printf("%d 客户端发送数据:%s \n", i, buffer);
    
                            write(i, buffer, str_length);//将数据发送回客户端
    
                        }
    
                    }
    
                }
    
            }
    
     
    
        }
    
     
    
        return 0;
    
    }
    
  • 相关阅读:
    Building a flexiable renderer
    Indirect Illumination in mental ray
    我的心情
    Cellular Automata
    Subsurface Scattering in mental ray
    Shader Types in mental ray
    BSP Traversal
    我的渲染器终于达到了MR的速度
    How to handle displacement and motion blur
    说明
  • 原文地址:https://www.cnblogs.com/ruier/p/15615781.html
Copyright © 2011-2022 走看看