• 阻塞与非阻塞个人小结


       1.connect函数响应中断返回后仍然回到函数的调用。
           实践证明,对于一个非阻塞的socket,如果在调用connect函数时,如果发生中断,这函数响应中断,但当中断返回时,继续connect函数的调用,直到connect超时失败或接收到错误ICMP包或连接成功

            2.accept()
            如果侦听进程是非阻塞模式工作,当调用accept()函数接收来自客户端的请求后,返回的socket套接字,默认为阻塞的工作模式。

    一、阻塞模型
        可能发生阻塞的套接口调用分为四种:
        1>.输入操作:read、readv、recv、recvfrom和recvmsg函数
        2>.输出操作:write、writev、send、sendto和sendmsg函数
        3>.接收外来连接:accept()函数
        4>.初始化外出的连接:connect()函数

    二、I/O模型
        1.阻塞I/O
        2.非阻塞I/O
        3.I/O复用(select函数)
        4.信号驱动I/O(SIGIO)
        5.异步I/O

    三、I/O复用模型的应用场合
        1.当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。
        2.一个客户同时处理多个套接口
        3.如果一个TCP服务器既要处理侦听套接口,又要处理已连接套接口,一般也要用到I/O复用。
        4.如果一个服务器既要处理TCP,又要处理UDP,一般也要使用I/O复用。
        5.如果一个服务器要处理多个服务或者多个协议(inetd守护进程)。

    四、拒绝服务型攻击
        服务器某一个时刻阻塞于只处理单个客户,而不能处理其他客户的需求,这就导致了拒绝服务型攻击,可能的解决办法是:(a)使用非阻塞I/O模型;(b)让 每个客户由单独的控制线程提供服务(例如,创建子进程或线程来为每个客户提供服务);(c)对I/O操作设置超时。

    五、connect()函数
       
    1.阻塞模式
        客户端调用connect()函数将激发TCP的三路握手过程,但仅在连接建立成功或出错时才返回。返回的错误可能有以下几种情况:
        1>.如果TCP客户端没有接收到SYN分节的响应,则返回ETIMEDOUT,阻塞模式的超时时间在75秒(4.4BSD内核)到几分钟之间。
        2>.如果对客户的SYN的响应时RST,则表明该服务器主机在我们指定的端口上没有进程在等待与之连接(例如服务器进程也许没有启动),这称为硬错,客户一接收到RST,马上就返回错误ECONNREFUSED.
        3>.如果某客户发出的SYN在中间的路由器上引发了一个目的地不可达ICMP错误,多次尝试发送失败后返回错误号为EHOSTUNREACH或ENETUNREACH.

    附加:产生RST的三种情况,一是SYN到达某端口但此端口上没有正在侦听的服务器、二是TCP想取消一个已有连接、三是TCP接收了一个根本不存在的连接上的分节。

    2.非阻塞模式
        采用非阻塞的工作模式要考虑一下两种情况:
    1>.如果是连接本机,则调用connect()函数会立刻建立。
    2>.如果服务器是网络中的用户,则调用connect()函数需要从几个毫秒的局域网到几百毫秒或几秒的广域网。并且函数会立刻返回EINPROCESS错误,但TCP通信的三路握手过程正在进行,所以可以使用select函数来检查这个连接是否建立成功。
        源自Berkeley的实现有两条与select函数和非阻塞相关的规则:
    1>.当连接成功建立时,描述字变成可写。
    2>.当连接建立出错时,描述字变成即可读又可写。

    六、accept()函数
    1.阻塞模式
        如果在一个阻塞套接口上调用accept()函数,而且没有新的连接,进程会进入睡眠状态。

    2.非阻塞模式
        如果在一个非阻塞套接口上调用accept()函数,而且没有新的连接,将返回EWOULDBLOCK错误。

    3.一种非阻塞模式例子的问题及解决办法
        问题描述:在服务器端侦听套接口采用阻塞的方式工作,并且使用select检测是否有已经建立起的连接,如果有则调用accept()函数接收该连接,问 题是如果客户端首先调用connect()函数连接服务器后立刻又调用close()函数关闭该连接,而在服务器端,在select()函数返回和调用 accept()函数之间,接收到客户端的断开,则会删除该套接口在已连接套接口中的内容,所以服务器将会阻塞在accept()函数,直到有客户连接才 返回。
        解决办法:(1).如果用select来获知何时有连接已就绪可以accept时,总是把侦听套接口置为非阻塞,同时(2).在后面的accept调用中 忽略以下错误:EWOULDBLOCK(Berkeley的实现在客户放弃连接时出现的错误)、ECONNABORTED(Posix.1g的实现在客户 放弃连接时出现的错误)、EPROTO(SVR4的实现在客户放弃连接时出现的错误)和EINTR(如果信号被捕获)。

    七、select()函数
        select()函数准备好读的条件:
        1>.套接口有数据可读
        2>.该连接的读这一半关闭(也就是接收了FIN的TCP连接)。对这样的套接口进行读操作将不阻塞并返回0(也就是返回EOF)。
        3>.该套接口是一个侦听套接口且已完成的连接数不为0。
        4>.其上有一个套接口错误待处理,对这样的套接口的读操作将不阻塞并返回-1,并设置errno,可以通过设置SO_ERROR选项调用getsockopt函数获得。

        select()函数准备好写的条件:
        1>.套接口有可用于写的空间。
        2>.该连接的写这一半关闭,对这样的套接口进行写操作将产生SIGPIPE信号。
        3>.该套接口使用非阻塞的方式connect建立连接,并且连接已经异步建立,或则connect已经以失败告终。
        4>.其上有一个套接口错误待处理。

    八、read()函数和recv函数
        read()函数返回值代表的意义:
        1>.如果对方TCP发送数据,则套接口就变为可读且read返回大于0的值(即数据的字节数)。
        2>.如果对方TCP发送一个FIN(对方进程终止),套接口就变为可读且read返回0(文件结束)。
        3>.如果对方TCP发送一个RST(对方主机崩溃并重新启动),套接口就变成可读且read返回-1,返回的错误号errno为ECONNRESET。


    九、write()函数和send函数
        如果向一个接收了FIN的套接字进行写操作是可行的,但如果向一个接受了RST的套接字进行写操作则是致命的,内核会向该进程发送一个SIGPIPE信号,返回EPIPO,该错误类型默认为终止进程。


    SIGPIPE信号
        向一个接受了RST的套接字进行写操作时,内核会向该进程发送一个SIGPIPE信号,该信号的缺省行为是终止进程,因此进程必须捕获它以免被不情愿的终止。
       


    5、 Linux中Socket的数据结构
    (1) struct sockaddr { //用于存储套接字地址
    unsigned short sa_family;//地址类型
    char sa_data[14]; //14字节的协议地址
    };
    (2) struct sockaddr_in{ //in 代表internet
    short int sin_family; //internet协议族
    unsigned short int sin_port;//端口号,必须是网络字节顺序
    struct in_addr sin_addr;//internet地址,必须是网络字节顺序
    unsigned char sin_zero;//添0(和struct sockaddr一样大小
    };
    (3) struct in_addr{
    unsigned long s_addr;
    };

  • 相关阅读:
    Windows Server 2003中不能安装MSN的解决方法
    招新人的一个标准
    SVN源代码服务器 证书通不过时的解决办法
    项目风险控制
    项目与团队管理体会
    季羡林老先生百年为人处世哲学
    李一男2003年在港湾给开发人员培训时的语录
    项目管理中的一些想法
    poj 1236 Network of Schools
    poj 2528 Mayor's posters
  • 原文地址:https://www.cnblogs.com/xiaOt119/p/2566209.html
Copyright © 2020-2023  润新知