有关网络编程的一些面试

1,首先说明socket是什么??

      我们知道:信息的交互需要涉及到tcp的四层模型

     

       从上图可以看到:底层的东西已经被内核实现了,即我们通常意义上的内核协议栈(传输层,网络层,链路层),最上面的Application(应用层)是我们用户所要实现的,它是属于用户进程的一部分,工作在用户空间,那么用户空间的程序要想访问内核,使用内核的服务,就需要一个接口,去访问所需要的服务,对于网络编程来说,这个接口就是套接口(Socket)。

       Socket:可以看作用户进程和内核网络协议栈编程(交互)接口

       Socket:不仅可以在同一台主机上进行通信,也可以在网络上不同的主机间进行通信,也可以异构(软硬件平台不同)进行通信(手机qq和PC机上的qq进行通信,手机的系统是ARM,而PC机是x86)

       全双共的,可以从A主机到达B主机,也可以从B主机到达A主机 ,跟管道不同


2,数据的通信的过程到底是什么样的???

      类似与上图,当主机A要想向主机B发送信息的过程中,首先是应用层通过套接口将要发送的信息给传输层,选择以什么协议传送(tcp,udp)并加入首部,传递给网络层,加入IP首部,构成IP报文,继续传递给链路层,交由以太网传递出去,通过路由器等等,,,(如上,加入首部的过程就是封装)

      当数据到达对等方之后,以太网接受到了数据帧,数据需要想上层传输,此刻,数据需要根据数据帧当中的类型字段来进行传递,如果是ARP的话,那就传输给链路层的ARP协议进行处理,如果是RARP协议的话,那么就传输给链路层的RARP协议进行处理,如果是IP协议的话,那么就传递给网络层中的IP协议进行处理,同理:IP协议的头部也有一个类型,承载着具体的协议,如果是TCP的话,那么就传递给运输层的TCP协议进行处理,如果是UDP的话,那么也就给TCP协议进行处理,并且去掉IP首部,紧接着去掉TCP首部,根据端口号,将信息传递给具体的进程。这就是我们通信的整个过程,如上:去掉首部的过程就是解封装。


3,ICMP,ARP协议都属于那些层??

      ICMP协议(Internet Control Message Protocol,Internet控制消息协议),它的功能是报告无法传送的数据包的错误,并帮助对这些错误进行解答。属于“网络层”,是所有TCP/IP协议网络的核心。

      ARP协议(Address Resolution Protocol,地址解析协议),属于IPv4协议族,属于数据链路层,功能是将IP地址解析为对应的MAC地址

      RARP协议(Reverse ARP,反向ARP协议),功能是将MAC地址解析为对应的IP地址。属于数据链路层


4,套接字类型

         流式套接字 (SOCK_STREAM)

      提供面向连接的,可靠的数据传输服务,数据误差错,无重复的发送,且按发送顺序接受

      数据报式套接字(SOCK_DGRAM)

      提供无连接服务。不提供无错保证,数据可能丢失或重复,并且接受顺序混乱

      原始套接字(SOCK_RAW)

      跨越运输层,没有什么tcp,udp,直接到达网络IP层


5,在通信的过程中,路由器是如何将数据转发出去的,用到了那些层???

      假如:用户主机H1通过电话线上网,中间经过三个路由器(R1,R2,R3)连接到远程主机H2。所经过的网络可以是各种的,如:电话网,局域网,广域网。当主机H1向H2发送数据时,从协议的层次来看,数据的流动如下图,数据进入路由器后要先从物理层上到网络层,在转发表中找到下一跳的地址后,再下到物理层转发出去。因此,数据从主机H1传送到H2需要在路径中的各结点的协议栈向上和向下流动多次

     

        实际转发如下:

       


6,关于客户端服务端终止应答的情况

      在TCP客户/服务器模型中:通信的双方都可以来调用close函数来进行终止,

      客户端先关闭:会发送一个文件结束的通知,相当与发送了一个EOF,会导致read返回等于0,然后此刻服务端就

      会意识到客户端已经关闭,所以服务端也就会调用相应的close来退出

      服务端先关闭:如果我们先结束了服务器(ctrl+c),那么客户端是不会立即退出的,可是在发一次数据便会自动退出,这是因为在正常通信中,服务器关闭了连接,那么客户端会正常接收到EOF,,如果对这个连接用epoll或者select进行监听,可以马上得知服务器关闭了连接。否则就定时向服务器发心跳探测,不然是不太可能得知服务器目前的状态的。之所以你现在不会立刻发现问题是因为服务器退出后,客户端需要靠下一次send才会触发问题,因为这时候连接已关闭,而客户端继续写,会产生SIGPIPE异常,而这个异常的默认动作是进程终止,所以你的客户端退出了。

     回射客户/服务器

     

     同样的关于启动过程,必须服务端先启动,如果客户端先启动当执行到connect的过程中就会出错的,那是因为那个过程要绑定,找不到目标,所以会出错:

     connect: Connection refused


7,主动套接字,被动套接字,LISTEN

     当socket函数创建一个套接字时,它被假设为一个主动套接字,也就是说,它是将调用connect发起连接的客户套接字。但是如果执行listen的话(调用应该在socket和bind函数之后,accept之前),会把一个未连接的套接字转换成一个被动套接字,指示内核应接受指向给套接字的连接请求,状态:CLOSE--->LISTEN

      

#include <sys/socket.h>

int listen(int sockfd, int backlog);
返回:成功为0,若出错则为-1
关于其中的backlog参数,我们必须充分的认识到内核为任何一个给定的监听套接字维护两个队列

         1,未完成连接队列(incomplete connection queue),每个这样的SYN分节对应其中一项:已由某个客户发出并到达服务器,而服务器正在等待完成相应的TCP三路握手过程。这些字节处于SYN_RCVD状态

         2,已完成连接队列(completed connection queue),每个已完成TCP三路握手过程的客户对应其中一项。这些套接字处于ESTABLISHED状态

         (图片摘自:UNIX网络编程卷1,84页)

         每当在未完成连接队列中创建一项时:来自监听套接字的参数就复制到即将建立的连接中。连接的创建机制是完全自动的,无需服务器进程插手,如下:

         

        当来自客户的SYN到达时,TCP在未完成连接队列中创建一个新项,然后响应以三路握手的第二个分节:服务器的SYN响应,其中稍带对客户SYN的ACK。这一项一直保留在未完成连接队列中,直到三路握手的第三个分节(客户对服务器SYN的ACK)到达或者该项超时为止。如果三路握手正常,该项就从未完成队列移到已完成连接队列的队尾。当进程调用accept时,已完成连接队列中的队头返回给进程,或者如果该队列为空,那么进程将被投入睡眠,知道TCP在该队列中放入一项才唤醒它。。。。


        accept

        

#include <sys/socket.h>

int accept(int sockfd, struct sockaddr * cliaddr, socklen_t *addrlen);
               返回:成功(非负描述符,出错为-1)
        在讨论accept函数时,前面应该已经调用过socket函数,会创建一个套接字,在bind,listen之后,变成了监听套接字,称accept的返回值为已连接套接字。区分这两个套接字非常重要。一个服务器通常仅仅创建一个监听套接字,它在该服务器的生命期内一直存在。内核为每个由服务器进程接受的客户连接创建一个已连接套接字(也就是对于它的TCP三路握手过程已经完成)。当服务器完成对某个给定客户的服务时,相应的已连接套接字就被关闭。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值