电话面试中遇到的一些不熟悉的知识点的总结

1.  什么是系统调用

      系统调用system call),又稱為系統呼叫,指运行在使用者空間程序操作系统内核请求需要更高权限运行的服务。 系统调用提供了用户程序与操作系统之间的接口。大多数系统交互式操作需求在内核态执行。如设备IO操作或者进程间通信。

     操作系统的进程空间可分为用户空间内核空间,它们需要不同的执行权限。其中系统调用运行在内核空间系统调用和普通库函数调用非常相似,只是系统调用由操作系统内核提供,运行于内核核心态,而普通的库函数调用由函数库或用户自己提供,运行于用户态。

     

操作系统实现的所有系统调用所构成的集合即程序接口或应用编程接口(Application Programming Interface,API)。是应用程序同系统之间的接口。
操作系统的主要功能是为应用程序的运行创建良好的环境,为了达到这个目的,内核提供一系列具备预定功能的多内核函数,通过一组称为系统调用(system call)的接口呈现给用户。系统调用把应用程序的请求传给内核,调用相应的的内核函数完成所需的处理,将处理结果返回给应用程序,如果没有系统调用和内核函数,用户将不能编写大型应用程序。
Linux系统调用,包含了大部分常用系统调用和由系统调用派生出的的函数
包括:进程控制,文件系统控制,文件系统操作,内存管理,网络管理,socket控制,用户管理,进程通信。、
Linux下进程间通信的几种主要手段简介:

    1.管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信; 

    2. 信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;Linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数); 

    3.报文(Message)队列(消息队列):消息队列是消息的链接表,包括Posix消息队列systemV消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。

    4.共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。 

   5. 信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。 

   6. 套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。 

2.内存泄漏和缓冲区溢出

内存泄漏:
解释:内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。即所谓内存泄漏。简单地说就是申请了一块内存空间,使用完毕后没有释放掉。它的一般表现方式是程序运行时间越长,占用内存越多,最终用尽全部内存,整个系统崩溃。由程序申请的一块内存,且没有任何一个指针指向它,那么这块内存就泄露了。
内存泄漏可以分为4类:

常发性内存泄漏

发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
偶发性内存泄漏
发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
一次性内存泄漏
发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块且仅一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。
隐式内存泄漏
程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天、几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。
表现
cpu资源耗尽:估计是机器没有反应了,键盘,鼠标,以及网络等等。这个在windows上经常看见,特别是中了毒。
进程id耗尽:没法创建新的进程了,串口或者telnet都没法创建了。
硬盘耗尽: 机器要死了,交换内存没法用,日志也没法用了,死是很正常的。
内存泄漏或者内存耗尽:新的连接无法创建,free的内存比较少。发生内存泄漏的程序很多,但是要想产生一定的后果,就需要这个进程是无限循环的,是个服务进程。当然,内核也是无限循环的,所以,如果内核发生了内存泄漏,情况就更加不妙。内存泄漏是一种很难定位和跟踪的错误,目前还没看到有什么好用的工具(当然,用户空间有一些工具,有静态分析的,也会动态分析的,但是找内核的内存泄漏,没有好的开源工具)
内存泄漏和对象的引用计数有很大的关系,再加上c/c++都没有自动的垃圾回收机制,如果没有手动释放内存,问题就会出现。如果要避免这个问题,还是要从代码上入手,良好的编码习惯和规范,是避免错误的不二法门。
一般我们常说的内存泄漏是指堆内存的泄漏。
堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显示释放的内存。
应用程序一般使用malloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。

缓冲区溢出
      缓冲区溢出攻击有多种英文名称:buffer overflow,buffer overrun,smash the stack,trash the stack,scribble the stack, mangle the stack, memory leak,overrun screw;它们指的都是同一种攻击手段。
概念:缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量溢出的数据覆盖在合法数据上,理想的情况是程序检查数据长度并不允许输入超过缓冲区长度的字符,但是绝大多数程序都会假设数据长度总是与所分配的储存空间相匹配,这就为缓冲区溢出埋下隐患.操作系统所使用的缓冲区 又被称为"堆栈". 在各个操作进程之间,指令会被临时储存在"堆栈"当中,"堆栈"也会出现缓冲区溢出。
危害:缓冲区溢出中,最为危险的是堆栈溢出,因为入侵者可以利用堆栈溢出,在函数返回时改变返回程序的地址,让其跳转到任意地址,带来的危害一种是程序崩溃导致拒绝服务,另外一种就是跳转并且执行一段恶意代码,比如得到shell,然后为所欲为。

溢出的原理

通过往程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈造成程序崩溃或使程序转而执行其它指令,以达到攻击的目的。造成缓冲区溢出的原因是程序中没有仔细检查用户输入的参数。例如下面程序:
void function(char *str) {
char buffer[16];
strcpy(buffer,str);
}
上面的strcpy()将直接把str中的内容copy到buffer中。这样只要str的长度大于16,就会造成buffer的溢出,使程序运行出错。存在象strcpy这样的问题的标准函数还有strcat(),sprintf(),vsprintf(),gets(),scanf()等


3.单链表的一些有意思的题目

3.1如何快速找到 未知长度单链表的中间节点

思想:我们大家首先可以想到的方法肯定是:首先遍历一遍单链表以确定单链表的长度L。然后再次从头节点出发循环L/2次找到单链表的中间节点。算法复杂度为O(L+L/2)=O(3L/2)。
但是可以有一个巧妙的方法来解决这个问题,思想大致如下:
设置两个指针* fast、*slow都指向单链表的头节点。其中* fast的移动速度是* slow的2倍。当* fast指向末尾节点的时候,slow正好就在中间了 。快慢指针在解决单链表环问题的时候是非常有用的 ,下面的题目中我们会再次用到快慢指针。看程序的C代码:

//head 代表单链表中的第一个节点,没有头节点
node * FindHalfNode(node *head)
{
    node * fast ;
    node * slow;
    fast = slow = head;//初始都指向单链表的第一个节点
    while(fast ->next != NULL)
    {
        if(fast -> next -> next != NULL)
        {
            slow = slow -> next;
            fast = fast ->next -> next;
        }
        else
            fast = fast -> next;

    }
    return slow;
}

如有错误,欢迎指出,gratitude~

3.2有一个单链表,其中可能有一个环,也就是某个节点的next指向的是链表中在它之前的节点,这样在链表的尾部形成一环。两个问题:1、如何判断一个链表是不是这类链表?2、如果链表为存在环,如果找到环的入口点?

1) 判断单链表中是否存在一个环,这个时候我们上面提到的快慢指针就可以用到了。

设置两个指针(fast, slow),初始值都指向头,slow每次前进一步,fast每次前进二步,如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针必定相遇。(当然,fast先行头到尾部为NULL,则为无环链表)程序如下:
//head 代表单链表中的第一个节点,没有头节点
boos IsExitsLoop(node *head)
{
    node * fast ;
    node * slow;
    fast = slow = head;//初始都指向单链表的第一个节点
    while(fast -> next != NULL && fast != NULL)
    {
        slow = slow -> next;
        fast = fast ->next ->next;
        if(slow == fast )
            break;

    }
    if(fast ==NULL || fast ->next == NULL)
        return false;//无环返回false
    else
        return true;//有环则返回 true
}   

2) 如何找到环的入口节点(转载)   地址: http://hi.baidu.com/iwitggwg/item/7ad684119a27fefc9c778a5c


假设链表存在环,则fast和slow两指针必然会在slow对链表完成一次遍历之前相遇,证明如下:

slow首次在A点进入环路时,fast一定在环中的B点某处。设此时slow距head长为x,B点距A点长度为y,环周长为s。因为fast和slow的步差为1,所以slow前行距离为y的时候,恰好会被fast在M点追上。因为y<s,所以slow尚未完成一次遍历。

 

有人对fast和slow的步长作了不同的设置来改善算法的效率,其实采用别的步长有可能使两指针无法在完成第一次遍历之前相遇,因此步长1和2是一个最优的选择。

假设slow行进了x并在A点进入环路时,fast在环中已经行进了n圈来到B点(n>=0),其行进距离为2x,则可得到如下等式:2x = x +ns+s-y,即x=(n+1)s-y

若此时再设置一个指向头节点的指针p,而slow在M处,当p行进了x来到A点时,M行进了x=(n+1)s-y,恰好也来到A处,即x长度可知。算法如下:

int CircleLength = -1;
Node FindCircle(Node* head)
{
    Node *slow = head;
    node *fast = head;
    int xy=0, n=0;
    while(fast != null)
    {
            fast = fast -> next;
            if(fast == null)
            {
                   return null;
            }
            fast = fast -> next;
            slow = slow -> next;
            
            xy++;
            if(slow == fast) //如果找到碰撞的点
            {
                   Node *p = head;
                   Node *m = slow;
                   while(p != slow)
                   {
                           p = p -> next;
                           slow = slow -> next;
                           if(slow == m)
                                 n++;
                   }
                   CircleLength = xy/(n+1);
                   return p;
            }
    }
    return null;
}


3.3 如何判断两个单链表中有相交的节点,并且如果有相交节点的话,我们如何找到相交节点。


 一、将其中一个链表首尾相连,检测另外一个链表是否存在环,如果存在,则两个链表相交,而检测出来的依赖环入口即为相交的第一个点。

       二、如果两个链表相交,那个两个链表从相交点到链表结束都是相同的节点,我们可以先遍历一个链表,直到尾部,再遍历另外一个链表,如果也可以走到同样的结尾点,则两个链表相交。

这时我们记下两个链表length,再遍历一次,长链表节点先出发前进(lengthMax-lengthMin)步,之后两个链表同时前进,每次一步,相遇的第一点即为两个链表相交的第一个点。


4.内存池的概念和使用


内存池(Memory Pool)是一种内存分配方式。        通常我们习惯直接使用new、malloc等API申请分配内存,这样做的缺点在于:
1.调用malloc/new,系统需要根据“最先匹配”、“最优匹配”或其他算法在内存空闲块表中查找一块空闲内存,调用 free/delete,系统可能需要合并空闲内存块,这些会产生额外开销
2.频繁使用时会产生大量内存碎片,从而降低程序运行效率
3.容易造成内存泄漏
内存池则是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是:
1.尽量避免了内存碎片,使得内存分配效率得到提升。
2.尽量避免内存泄漏
内核中有不少地方内存分配不允许失败. 作为一个在这些情况下确保分配的方式, 内核开发者创建了一个已知为内存池(或者是 "mempool" )的抽象. 一个内存池真实地只是一类后备缓存, 它尽力一直保持一个空闲内存列表给紧急时使用.

  5.SQL注入攻击

   概念:所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击.它是目前比较常见的针对数据库的一种攻击方式。在这种攻击方式中,攻击者会将一些恶意代码插入到字符串中。然后会通过各种手段将该字符串传递到SQLServer数据库的实例中进行分析和执行。只要这个恶意代码符合SQL语句的规则,则在代码编译与执行的时候,就不会被系统所发现当应用程序使用输入内容来构造动态sql语句以访问数据库时,会发生sql注入攻击。如果代码使用存储过程,而这些存储过程作为包含未筛选的用户输入的字符串来传递,也会发生sql注入


6 linux  下文件的权限


文件权限:

这个面试的时候问到Linux 下面 好多简单的命令竟然忘记了,唉,看来还是自己使用的不够熟练。这个太失望了。
Linux是一种多用户操作系统,为了确保在多用户环境下的系统运转的安全性,Linux使用用户权限机制对系统进行管理,这种管理主要是通过文件管理机制完成的。
       Linux
对每个文件设置一个16位数字来完成对文件的存取控制,这个数字称为文件属性。如同我们在前面说的那样,Linux并不使用文件名来区分文件的类型,文件的性质用文
件属性来描述。在这个16位数字中有9用于设置用户对文件的存取控制,3位用于对可执行文件进行特殊处理,另外3位用于设置文件的类型。
文件类型包括:1. 目录(d )             2.普通文件( - )          3.链接(l )            4.字符文件 (c)              5.块设备(b)
可以使用ls -l 命令查看文件的权限和属性,来看一下我机器上的


可以看到以d开头的是目录文件(蓝色表示) -开头的就是普通文件了。
接下来的九个字母代表存取控制,从左至右每三个为一组,分成三组,分别代表文件的拥有者,同组用户和其他用户。 其中每组对应的 r为可读,w为可写,x为可执行  -表示该为没有被设置。
文件的拥有者是文件逻辑上的主人,只有他才能修改文件的属性。一般来说每当有人新建一个文件,他就自动地成为文件的拥有者。则 表示 chenhao是该用户的拥有者(第3栏),同组用户是在Linux用户管理中定义的该文件所属组的用户。所属组显示在ls –l输出的第四栏。(这里还是chenhao)。 则这个例子表示 文件拥有者和组用户 只可以读写该文件,没有权限执行该文件,最后其他用户的权限 是只能读该文件。

更改文件权限:

 文件的拥有者可以用chmod命令更改文件的属性,也可以通过更改文件的属主把文件交给他人控制。

  1.chmod命令的用法是    :chmod 属性字 文件名

        属性字有两种用法,最基本的用法是使用字母,用u(这个不知道如何用英文代表。。。)g(group)o(other users)分别代表文件拥有者,组用户和其他用户,+-号用于调整权限。例如,要给A文件加上拥有者可以执行的权限,命令为   chmod u+x A,取消其他用户可读的命令为 chmod o-r A

  2. chmod 命令使用数字修改权限

  chmod另外的一种用法是使用数字,为拥有者,组用户和其他用户分别计算一个数,计算规则是r=4,w=2,x=1,然后相加(例如,r+x=5),最后将三个数连到一起,例如为A分配一个rwxrw-r—的属性的命令是  chmod 764 A  (rwx   rw-   r—)

7.TCP三次握手与四次挥手详解(转载于:http://www.centos.bz/2012/08/tcp-establish-close/

这个问题虽然知道,但是回答的不是很好,在此mark一下

相对于SOCKET开发者,TCP创建过程和链接折除过程是由TCP/IP协议栈自动创建的.因此开发者并不需要控制这个过程.但是对于理解TCP底层运作机制,相当有帮助.

而且对于有网络协议工程师之类笔试,几乎是必考的内容.企业对这个问题热情之高,出乎我的意料:-)。有时上午面试前强调这个问题,并重复讲一次,下午几乎每一个人都被问到这个问题。

因此在这里详细解释一下这两个过程。

TCP三次握手

所谓三次握手(Three-way Handshake),是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。

三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号确认号并交换 TCP 窗口大小信息.在socket编程中客户端执行connect()时。将触发三次握手。

第一次握手:
客户端发送一个TCP的SYN标志位置1的包指明客户打算连接的服务器的端口,以及初始序号X,保存在包头的序列号(Sequence Number)字段里。

第二次握手:
服务器发回确认包(ACK)应答。即SYN标志位和ACK标志位均为1同时,将确认序号(Acknowledgement Number)设置为客户的I S N加1以.即X+1。

第三次握手.
客户端再次发送确认包(ACK) SYN标志位为0,ACK标志位为1.并且把服务器发来ACK的序号字段+1,放在确定字段中发送给对方.并且在数据段放写ISN的+1

SYN攻击
在三次握手过程中,服务器发送SYN-ACK之后,收到客户端的ACK之前的TCP连接称为半连接(half-open connect).此时服务器处于Syn_RECV状态.当收到ACK后,服务器转入ESTABLISHED状态.


Syn攻击就是 攻击客户端 在短时间内伪造大量不存在的IP地址,向服务器不断地发送syn包,服务器回复确认包,并等待客户的确认,由于源地址是不存在的,服务器需要不断的重发直 至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,目标系统运行缓慢,严重者引起网络堵塞甚至系统瘫痪。
Syn攻击是一个典型的DDOS攻击。检测SYN攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击.在Linux下可以如下命令检测是否被Syn攻击
netstat -n -p TCP | grep SYN_RECV
一般较新的TCP/IP协议栈都对这一过程进行修正来防范Syn攻击,修改tcp协议实现。主要方法有SynAttackProtect保护机制、SYN cookies技术、增加最大半连接和缩短超时时间等.
但是不能完全防范syn攻击。



TCP 四次挥手
TCP的连接的拆除需要发送四个包,因此称为四次挥手(four-way handshake)。客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close()操作即可产生挥手操作。




 连接终止协议(四次挥手)

   由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
 (1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。
 (2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
 (3) 服务器关闭客户端的连接,发送一个FIN给客户端。
 (4) 客户段发回ACK报文确认,并将确认序号设置为收到序号加1。

TCP状态转换图:


解释一下状态:
CLOSED: 这个没什么好说的了,表示初始状态。
LISTEN: 这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。
SYN_RCVD: 这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。
SYN_SENT: 这个状态与SYN_RCVD遥想呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。

ESTABLISHED:这个容易理解了,表示连接已经建立了。
FIN_WAIT_1: 这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。
FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。

TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。

CLOSING: 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。
CLOSE_WAIT: 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。
LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。
最后有2个问题的回答,我自己分析后的结论(不一定保证100%正确)

1、 为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

2、 为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?
这是因为:虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。

大概 就记下了这么多,以后有想起来随时添加~如发现错误请指出,gratitude~




     

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值