• 2018-2019-1 20165201 《信息安全系统设计基础》第8周学习总结


    2018-2019-1 20165201 《信息安全系统设计基础》第8周学习总结


    学习内容总结

    第11章 网络编程(刘念老师课上讲过)

      TCP协议是面向连接的协议,它提供了一系列的数据纠错功能,可以保证数据在网络上传输及时、无误给接收方。因此面向连接协议的Socket编程模型应用最为广泛,基于连接协议的服务是设计客户端/服务器应用程序时的标准。编程模型如图所示

    模型中,
      服务器端的处理
    (1)使用socket系统调用,生成一个TCP协议模块与应用程序之间进行通信的套接字;使用bind系统调用指定端口号;
    (2)使用bind系统调用指定端口号;
    (3)使用listen系统调用,指定连接接收队列的长度,并等待来自客户端的连接请求。
      前三步完成了启动服务器程序的工作。一旦listen监听到有客户端的连接,就调用accept接收连接。
      希望与服务器通信的进程称为客户,客户所运行的计算机环境称为客户端,有时两个概念混用。
      客户端的处理
    (1)使用socket系统调用,打开TCP协议模块与应用程序之间的通信线路;
    (2)使用connect系统调用,指定IP地址和端口号,和服务器相应的服务应用程序建立TCP协议的连接请求;
      客户端和服务器程序在建立连接后,使用send和recv调用完成数据的发送和接收工作。等待数据传送结束后,各自调用close关闭套接字。
      使用TCP协议的Socket通信程序包括服务程序和客户程序。

    基于C的Socket编程相关函数和数据类型
    1.sockaddsockaddr_in结构:
    sockaddr 结构

    struct sockaddr  
    {
    	unsigned short sa_family;	/*地址族,AF_xxx有IPV4与IPV6等*/
    	char		sa_data[14];	/*14字节的协议地址*/
    };
    

    sa_family一般为AF_INET,表示Internet协议族,如是AF_UNIX表示UNIX协议簇;sa_data中包含该socket的IP地址和端口号。
    in_add结构,用来存储四字节的IP地址

    struct in_addr{
    	unsigned long	s_addr;
    };
    

    sockaddr_in结构

    struct sockaddr_in
    {
    	short int	sin_family;		/*地址族*/
    	unsigned short int	sin_port;	/*端口号*/
    	struct in_add 		sin_addr;	/*IP地址*/
    	unsigned char		sin_zero[8];	/*填充0以保持与struct sockaddr同样大小*/
    };
    

    该结构中sin_zero使得sockaddrsockaddr_in指针类型相互转换;sin_portsin_addr必须是网络字节顺序,因为它们被封装在包的IP和UDP层,而sin_family不发送到网络上可以是本机字节顺序。

    相关函数
    1.socket()函数
      该函数用于根据指定的地址族、数据类型和协议来分配一个套接字的描述字及其所用的资源。Socket函数原型为:
    int socket( int domain , int type , int protocol ) ;
    a、 参数domain指定地址描述,一般为AP_INET
    b、 参数type指定socket类型:SOCK_STREAMSOCK_DGRAM
    c、参数protocol通常为0;
    d、 函数返回值为一个整型socket描述符,在bind函数中调用。

    2.bind()函数
      该函数用于将一个本地地址与一个套接字绑定在一起。
    int bind( int sockfd , struct sockadd* my_addr , int addrlen) ;
    a、sockfd:socket描述符,使用socket函数返回值,将该socket与本机上的一个端口相关联。
    在设计服务器端程序是需要调用bind函数,以在该端口上监听服务请求;而客户端一般不需要调用bind函数,因为只需知道服务器IP地址,并不关心客户通过哪个端口与服务器建立连接,内核会自动选择一个未被占用的端口供客户端来使用。
    b、my_addr:指向包含本机IP地址及端口号等信息的sockaddr类型的指针。
    c、addrlensizeof( struct sockaddr)的值。
    d、bind函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码。

    3.connect()函数
      与远程服务器建立一个TCP连接。
    int connect(int sockfd, struct sockaddr* serv_addr, int addrlen);
    a、sockfd:目的服务器的socket描述符。
    b、serv_addr:指向包含目的服务器的IP地址及端口号的指针。
    c、addrlensizeof( struct sockaddr)的值。
    d、connect函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,进行服务器端程序设计时不需调用connect函数。

    4.listen()函数
      在服务器端程序中,当socket与某一端口绑定后,需要监听该端口,及时处理到达该端口上的服务请求。
    int listen(int sockfd, int backlog);
    a、sockfd:Socket系统调用返回的socket描述符。
    b、backlog:指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待接收backlog限制了队列中等待服务的请求数目,系统缺省值为20。
    c、listen函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码。

    5.accept()函数
      当某个客户端试图与服务器监听的端口连接时,该连接请求将排队等待服务器用accept接收它并为其建立一个连接。
    int accept(int sockfd, struct sockaddr* addr, int* addrlen);
    a、sockfd:被监听的socket描述符。
    b、addr:sockaddr类型的指针变量,用来存放提出连接请求服务的主机信息。
    c、accept函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,如果没有错误,accept()函数返回一个新想socket描述符,供这个新连接来实用,而服务器可以继续在以前的socket上监听,同时可以在新的socket描述符上进行数据发送和数据接收(sent()recv()操作)。

    6.sent()recv()函数
      用于在面向连接(TCP)的socket上进行数据传输。
    send()函数原型:
    int send(int sockfd, const void* msg, int len, int flags) ;
    a、sockfd:用于传输数据的socket描述符。
    b、msg:是一个指向要发送数据的指针。
    c、len:以字节为单位的数据的长度。
    d、flags:一般情况下置为0。
    e、函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,否则返回所发送数据的总数,该数字可能小于len中所规定的大小。
    recv()函数原型:
    int recv(int sockfd, void* buf, int len, unsigned int flags);
    a、sockfd:是接收数据的socket描述符。
    b、buf:是存放接收数据的缓冲区。
    c、len:以字节为单位的缓冲区的长度。
    d、flags:一般情况下置为0。
    e、函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,无错则返回读入的字节数,如果连接被中止,返回0。

    7.endto()recvfrom()函数
      这两个函数是利用数据报方式(UDP)进行数据传输。在无连接的数据报socket方式下,由于本地socket并没有与远程机器建立连接,所以在发送数据时应指明目的地址。
    sendto()原型:
    int sendto(int sockfd, const void* msg, int len, unsigned int flags, const struct sockaddr* to, int tolen);
    a、sockfd:用于传输数据的socket描述符。
    b、msg:是一个指向要发送数据的指针。
    c、len:以字节为单位的数据的长度。
    d、flags:一般情况下置为0。
    e、函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,否则返回所发送数据的总数,该数字可能小于len中所规定的大小。
    f、表示目的机器的IP地址和端口号。
    g、tolen:被赋值为sizeof(struct sockaddr)
    recvfrom函数原型:
    int recv(int sockfd, void* buf, int len, unsigned int flags, struct sockaddr* from, int fromlen);
    a、sockfd:是接收数据的socket描述符。
    b、buf:是存放接收数据的缓冲区。
    c、len:以字节为单位的缓冲区的长度。
    d、flags:一般情况下置为0。
    e、函数返回值:为-1表示遇到错误,并且errno中包含相应的错误码,无错则返回读入的字节数,如果连接被中止,返回0。
    f、from:保存源机器的IP地址和端口号。
    g、fromlen:常被赋值为sizeof(struct sockaddr)
    当对于数据报socket调用了connect()函数时,也可以用send()recv()进行数据传输,但该socket仍然是数据报socket,并利用传输层的UDP服务。但是在发送或接收数据报时,内核会自动为它加上目的地址和源地址信息。

    8.close()shutdown()函数
      当所有的数据操作结束后,可以调用close函数来释放该socket资源,从而停止在该socket上的任何数据操作。
      也可以调用shutdown函数,允许只停止在某个方向上的数据传输,而另一个方向上的数据传输继续进行。例如可以关闭某一个socket上的写操作uo允许继续在该socket上接收数据,直到读入所有数据。
      但是,shutdown函数并不关闭套接字所占用的所有资源,除非调用close函数来释放。
    看看两个函数原型:
    close(int sockfd);
    shutdown(int sockfd, int how);
    how参数的值和含义:
    0:不允许继续接收数据;
    1:不允许继续发送数据;
    2:不允许继续发送和接收数据。
    shutdown在操作成功时返回0,错误时返回-1,并置errno值。

    9.字节顺序转换函数
    htons():Host to Network Short的缩写,该函数将主机的无符合短整型数字节顺序转换成网络字节顺序。
    htonl():Host to Network Long的缩写,该函数将主机的无符合长整型数字节顺序转换成网络字节顺序。
    ntohs():Network to Host Short的缩写,该函数将无符号短整型数从网络字节顺序转换为主机字节顺序。
    ntohl():Network to Host long的缩写,该函数将无符号长整型数从网络字节顺序转换为主机字节顺序。


    第12章 并发编程

    并发:逻辑控制流在时间上重叠

    应用级并发作用:

    • 访问慢速I/O设备
    • 与人交互
    • 通过推迟工作以降低延迟
    • 服务多个网络客户端
    • 在多核机器上进行并行计算

    并发程序:使用应用级并发的应用程序

    构造并发程序的方法:

    • 进程(程序级并发)
    • 线程(函数级并发)
    • I/O多路复用

    基于进程的并发编程

      在接受连接请求之后,服务器派生一个子进程,这个子进程获得服务器描述符表的完整拷贝。子进程关闭它的拷贝中的监听描述符3,而父进程关闭它的已连接描述符4的拷贝,因为不再需要这些描述符了。这就得到了图中的状态,其中子进程正忙于为客户端提供服务。

    (照片尺寸问题,请全屏看图,后同)

      因为父子进程中的已连接描述符都指向同一个文件表表项,所以父进程关闭它的已连接描述符的拷贝是至关重要的。否则,将永远不会释放已连接描述符4的文件表条目,而且由此引起的存储器泄漏将最终消耗尽可用的存储器,使系统崩溃。

      现在假设在父进程为客户端1创建了子进程之后,它接受一个新的客户端2的连接请求,并返回一个新的已连接描述符(比如描述符5)如图所示。然后,父进程又派生另一个子进程,这个子进程用已连接描述符5为它的客户端提供服务,如图所示。此时,父进程正在等待下一个连接请求,而两个子进程正在形地为它们各自的客户端提供服务。

    基于I/O多路复用的并发编程
    并发事件驱动echo服务器中逻辑流的状态机:

    基于线程的并发编程

    线程:运行在进程上下文中的逻辑流

      每个线程都有它自己的线程上下文

    • 线程ID
    • 栈指针
    • 程序计数器
    • 通用目的寄存器
    • 条件码
        所有的运行在一个进程里的线程共享该进程的整个虚拟地址空间
        由于多个线程运行在单一进程中,因此共享这个进程虚拟地址空间的整个内容,包括它的代码、数据、堆、共享库和打开的文件

    多线程程序中的共享变量

      全局变量和static变量是存储在数据段,所以多线程共享之!由于线程的栈是独立的,所有线程中的自动变量是独立的。即使多个线程运行同一段代码总的自动变量,那么他们的值也是根据线程的不同而不同。

    • 线程内存模型
    • 将变量映射到内存
      1、全局变量
      2、本地自动变量
      3、本地静态变量
    • 共享变量

    学习进度条

    代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
    目标 2000行 20篇 200小时
    第一周 83/83 1/1 8/8
    第六周 75/158 2/3 10/18

    参考资料

  • 相关阅读:
    Hadoop 实现 TFIDF 计算
    关于Elasticsearch 使用 MatchPhrase搜索的一些坑
    SpringBoot jar包中资源加载问题
    gradle 将依赖打入Jar包的方法
    ES 在聚合结果中进行过滤
    Java c# 跨语言Json反序列化首字母大小写问题
    hadoop is running beyond virtual memory limits问题解决
    hadoop环境运行程序出现 Retrying connect to server 问题
    CSS的初步认识,基本选择器(CSS day1)
    day19 time模块
  • 原文地址:https://www.cnblogs.com/cbmwtsl/p/10017448.html
Copyright © 2020-2023  润新知