- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
Socket面试题及答案
一、基础概念题
面试官:你理解的Socket是什么?和TCP、UDP的关系是什么?
答:Socket其实是“网络通信的端点”,可以理解成操作系统给应用程序提供的“网络通信接口”。我们写代码时没法直接操作TCP/UDP协议栈,得通过SocketAPI(比如C的socket()函数、Java的Socket类)来调用系统能力。
关系上:TCP和UDP是传输层协议,负责数据的传输规则;Socket是“用这些协议通信的工具”——比如创建TCPSocket就是基于TCP协议建立连接,UDPSocket就是基于UDP协议发送数据,相当于“协议是路,Socket是车上的接口”。
面试官:TCPSocket和UDPSocket的核心区别是什么?实际开发中怎么选?
答:核心区别在“连接性”和“可靠性”:
TCPSocket:必须先三次握手建立连接(像打电话先接通),能保证数据有序、不丢不重(有ACK确认、重传机制),但速度稍慢、开销大;
UDPSocket:不用建立连接,直接发数据(像发短信),不保证可靠性,数据可能丢、可能乱序,但速度快、开销小。
选型看场景:比如文件传输、登录请求(需要确保数据到)用TCP;直播、DNS查询、物联网设备心跳(允许偶尔丢包,要低延迟)用UDP。
二、核心原理题
面试官:TCPSocket建立连接的三次握手,你能讲下过程吗?为什么需要三次而不是两次?
答:三次握手简单说就是“请求-确认-再确认”:
客户端发SYN包(说“我要连你”),进入SYN_SENT状态;
服务端收到后,回SYN+ACK包(说“我同意连,你也准备好”),进入SYN_RCVD状态;
客户端收到后,再发ACK包(说“好的,开始传数据吧”),双方进入ESTABLISHED状态。
为什么三次?主要是“确认双方的收发能力都正常”。如果两次的话,服务端发了SYN+ACK后就认为连接成了,但客户端可能没收到这个包(比如网络丢了),这时服务端会一直等客户端发数据,浪费资源;三次握手里,客户端的最后一个ACK能让服务端确认“客户端能收也能发”,避免这种资源浪费。
面试官:Socket编程里,阻塞和非阻塞有什么区别?实际用的时候会遇到什么问题?
答:区别在“调用SocketAPI时是否会卡住”:
阻塞Socket:比如调用recv()收数据时,如果没数据来,线程会一直等(卡住),直到有数据或出错;像早期的单线程服务端,一次只能处理一个客户端,就是因为accept()和recv()都是阻塞的。
非阻塞Socket:调用recv()时,如果没数据,会立刻返回错误(比如Linux下返回-1,错误码EAGAIN),线程不会等,可以去做别的事。
实际问题:非阻塞虽然能提高并发,但要不停轮询(比如循环调用recv()),浪费CPU;所以一般会配合IO多路复用(select/poll/epoll)用——比如epoll能监听多个非阻塞Socket,有数据时才通知线程处理,既不卡线程又不浪费CPU。
三、实战问题题
面试官:开发TCPSocket时,遇到“客户端断开连接但服务端没察觉”的情况,怎么解决?
答:这种情况常见于“客户端异常断连”(比如突然断电),因为TCP的四次挥手没正常执行,服务端会一直以为连接还在(处于ESTABLISHED状态),造成“僵尸连接”。
解决方法主要是加“心跳检测”:
方案1:用TCP自带的SO_KEEPALIVE选项(开启后,系统会每隔一段时间发心跳包),但缺点是参数(比如心跳间隔)由系统控制,不够灵活;
方案2:应用层自己实现心跳——比如客户端每隔10秒给服务端发一个“空包”(或固定格式的心跳包),服务端如果超过30秒没收到,就主动关闭连接。实际项目里更常用这个,因为能自定义逻辑(比如心跳包带设备状态)。
面试官:发送数据时,Socket的发送缓冲区满了会怎么样?怎么处理?
答:首先得知道:每个Socket都有系统分配的发送缓冲区(默认大小比如Linux下是16KB),调用send()时,数据先放进这个缓冲区,再由TCP协议栈慢慢发给对方。
如果是阻塞Socket:send()会卡住,直到缓冲区有空间(比如对方接收了数据,缓冲区数据被取走);
如果是非阻塞Socket:send()会立刻返回“发送失败”(错误码EAGAIN或EWOULDBLOCK),不会等。
处理方式:非阻塞场景下,遇到EAGAIN不要直接重试,应该把数据暂存在应用层的缓冲区里,等epoll通知“Socket可写”(缓冲区有空间)时,再
文档评论(0)