每日面经(十六)

文章讨论了TCP连接中的close_wait状态及其出现条件,客户端关闭连接后服务端未调用close()的影响,以及socket套接字的阻塞和非阻塞概念。同时,介绍了Linux系统中共享内存的使用方法和处理哈希表中哈希冲突的策略。

目录

1.TCP连接的close_wait状态有什么用?什么情况下会出现?

2.TCP,如果客户端关闭了连接,服务端没有调用close()函数会怎么样?

3.讲讲socket套接字的阻塞和非阻塞?

4.Linux系统如何使用共享内存?有哪些方式?

5.如何构造哈希表?哈希冲突了怎么办?


1.TCP连接的close_wait状态有什么用?什么情况下会出现?

在TCP连接中,CLOSE_WAIT状态指的是一个TCP连接中的一方(通常是客户端)已经发送了FIN数据包,即表示希望关闭连接,但是另一方(通常是服务器端)还没有发送FIN数据包,即表示还没有确认关闭连接。

CLOSE_WAIT状态的作用是等待服务器或者对方连接端的响应,一旦等到了响应,就会进入到最终的关闭状态,完成连接的关闭。

CLOSE_WAIT状态通常在以下情况下出现:

  1. 客户端发送了FIN数据包,请求关闭连接,但是服务器还没有响应;

  2. 客户端接收到服务器的FIN数据包,表示服务器请求关闭连接,但是客户端还有未发送完的数据,此时客户端会进入CLOSE_WAIT状态,等待发送完未发送的数据后关闭连接。

此外,如果服务器端在接收到客户端FIN数据包后并没有立即响应,而是需要进行一些处理后才能发送FIN数据包,此时客户端也会出现CLOSE_WAIT状态。

2.TCP,如果客户端关闭了连接,服务端没有调用close()函数会怎么样?

如果客户端关闭了连接,服务端没有调用close()函数,那么服务端在一定时间内也会检测到连接已经关闭,并进入CLOSE_WAIT状态。如果服务端在超时时间内没有关闭连接,连接会被自动断开。

具体来说,当客户端发送FIN数据包通知服务端关闭连接后,服务端接收到FIN数据包后,会进入CLOSE_WAIT状态。在这个状态下,服务端已经收到了客户端的断开连接请求,但还可以继续向客户端发送数据,直到所有数据都发送完毕为止。一旦服务端发送完所有数据,就会发送ACK确认数据包,并进入LAST_ACK状态,等待客户端的最后确认。如果服务端在超时时间内没有接收到最后确认,服务端会直接关闭连接。

总之,TCP连接的关闭需要双方都发送FIN数据包才能完成,如果某一方没有发送FIN数据包,那么对方会一直处于等待关闭连接状态,直到超时自动断开连接。

3.讲讲socket套接字的阻塞和非阻塞?

对于 Socket 套接字来说,阻塞(blocking)和非阻塞(non-blocking)是指针对套接字上的 IO 操作而言的。

在阻塞 IO 操作中,当应用程序调用 Socket 函数进行套接字 IO 操作时,如果没有数据可读或者缓冲区已满,应用程序将被阻塞,也就是说在数据到达之前,应用程序无法进行其它的操作。

在非阻塞 IO 操作中,当应用程序调用进程阻塞函数时,如果没有数据可读或者缓冲区已满,就会立即返回,而不是一直等待。应用程序需要不停地轮询,直到数据到达,或者在有数据到来之前可以做其它的事情。

非阻塞 IO 相对于阻塞 IO 来说具有一定的优点,比如可以轮询 IO 状态,可以在等待数据的同时做其它的事情。

从系统调用角度来说,可以通过设置 Socket 套接字的属性,将其设置为阻塞或者非阻塞的模式。可以调用fcntl()ioctl()等函数,或者使用setsockopt()函数来设置套接字的阻塞属性。

阻塞套接字相对于非阻塞套接字来说,对应用程序更加简单、易于理解。而非阻塞套接字虽然比较复杂,但能够提高程序的并发性,因此在实际开发中,根据实际需求选择合适的方式。

4.Linux系统如何使用共享内存?有哪些方式?

在Linux系统中,使用共享内存可以让不同进程之间共享同一块物理内存区域,从而实现高效的进程间通信(IPC)。下面介绍几种常用的共享内存方式:

  1. shmget():该函数可以创建或获取一个共享内存标识符(即共享内存对象),并返回一个与其关联的内存块的地址。

  2. shmat():该函数将通过shmget()函数得到的共享内存标识符关联的内存块映射到调用进程的地址空间中,从而使其可以访问该内存块。

  3. shmctl():该函数用于控制共享内存,可以对共享内存进行删除、修改权限等操作。

  4. shmdt():该函数将与共享内存关联的内存块从调用进程的地址空间中分离,使得进程不能再访问该内存块。

共享内存的使用过程通常包括以下步骤:

  1. 调用shmget()获取一个共享内存标识符;

  2. 通过shmat()将该共享内存映射到调用进程的地址空间中;

  3. 进程之间通过访问该共享内存块来实现数据交换;

  4. 调用shmdt()分离该共享内存块;

  5. 可以调用shmctl()删除或修改该共享内存。

需要注意的是,使用共享内存时需要保证访问该内存时的互斥性和同步性,否则可能会导致数据错误。另外还需要注意共享内存的大小和权限等问题。

5.如何构造哈希表?哈希冲突了怎么办?

哈希表是一种高效的数据结构,它支持快速的插入、删除和查找操作,通常用于实现各种缓存、数据库、编译器等工具。哈希表的核心思想是将关键字映射到一个唯一的、能够快速查找的地址空间,即哈希表的下标。下面介绍一种常见的哈希表构造方法和处理哈希冲突的技术。

1.构造哈希表

哈希表通常由一个数组和一个哈希函数组成。哈希函数将输入的关键字映射到一个数组下标,通过该下标快速访问哈希表中的数据项。一般来说,哈希函数应该满足以下要求:

(1) 散列值均匀分布,尽量避免出现冲突。

(2) 计算速度快,不过多地消耗时间和空间的资源。

(3) 映射地址随机性强,不易被预测或攻击。

2.处理哈希冲突

由于哈希表的下标是有限的,因此难免会出现两个或多个关键字映射到同一个下标的情况,即哈希冲突。为了解决这个问题,可以采用以下几种常见的技术:

(1) 链表法:将哈希表中每个元素设置为链表的头结点,哈希冲突时,将新的结点链接到对应的头结点下面。

(2) 开放定址法:在哈希冲突时,向后探测空闲的数组元素,找到可以插入的位置。例如,可选用线性探测或二次探测来查找空闲元素。

(3) 再哈希法:使用多个不同的哈希函数对于发生哈希冲突的关键字进行二次哈希,直到找到空位为止。

(4) 建立公共溢出区:在哈希表中预留一部分空间,专门用于存储发生冲突的元素。当哈希冲突发生时,将元素插入到该区域中,利用链表或其他数据结构管理该区域的元素。

综上所述,哈希表作为一种高效的数据结构,具有快速查找的优势,而哈希冲突的解决是实现哈希表的基础。不同的哈希冲突解决方案有其各自的优缺点,需要根据具体的应用场景来选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值