sangfor面试准备
(已拿offer)(已离职)
Linux网络编程
1.域套接字比流式套接字快的原因?
UNIX域套接字用于同一台pc上运行的进程之间通信,它仅仅复制数据,不执行协议处理,不需要增加删除网络报头,无需计算校验和,不产生顺序号,无需发送确认报文。
unix域套接字地址结构如下定义:
#include <sys/un.h>
struct sockaddr_un {
sa_family_t sun_family;/* AF_LOCAL */
char sun_path[104];/* 以空字符结尾的字符串 */
}
没有端口和IP地址等信息
2.connect实现了什么?UDP是否可以使用?
tcp使用connect函数,经过三次握手建立连接
UDP可以使用,在UDP收发数据有两种方式:
- socket->sendto/recvfrom
- socket->connect->send/recv
UDP socket使用connect仅仅是指定了唯一的IP地址和端口号,没有三次握手。这样做的目的是限制socket仅能与一个对端交换数据报。
3.TCP socket接收数据怎么实现的,recv的返回值
可以使用read或recv,recv函数的声明如下
/* Read N bytes into BUF from socket FD.
Returns the number read or -1 for errors.
This function is a cancellation point and therefore not marked with
__THROW. */
extern ssize_t recv (int __fd, void *__buf, size_t __n, int __flags);
返回值有:
- >0 成功接收的数据大小
- =0 对方连接关闭
- -1 错误,需要获取错误码errno
4.recv函数错误怎么处理,错误码errno有哪些?
while(1)
{
cnt = (int)recv(m_socket, pBuf,RECVSIZE, 0);
if( cnt >0 )
{
//正常处理数据
}
else
{
if((cnt<0) &&(errno == EAGAIN||errno == EWOULDBLOCK||errno == EINTR))
//这几种错误码,认为连接是正常的,继续接收
{
continue;//继续接收数据
}
break;//跳出接收循环
}
}
常见的错误码errno有
- EINTR 阻塞操作被取消阻塞的调用打断
- ETIMEOUT
- 操作超时
- 服务器做了读数据做了超时限制,读时发生了超时
- EAGAIN
- send返回值小于要发送的数据数目
- recv返回值小于请求的长度时说明缓冲区已经没有可读数据
- 当socket是非阻塞时,如返回此错误,表示写缓冲队列已满,可以做延时后再重试
- EWOULDBLOCK 资源暂时不可用
- EPIPE socket关闭
5.read/write和send/recv区别
在功能上,read/write是recv/send的子集。read/wirte是更通用的文件描述符操作,而recv/send在socket领域则更“专业”一些。
如果有如下几种需求,则read/write无法满足,必须使用recv/send:
- 为接收和发送进行一些选项设置
- 从多个客户端中接收报文
- 发送带外数据(out-of-band data)
6.tcp里面的time_wait状态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xuWfm0OF-1582258488789)(https://blog.jiar.vip/2017/08/24/TCP%E5%9B%9B%E6%AC%A1%E6%8C%A5%E6%89%8B%E7%AE%80%E4%BB%8B/tcp_hand_wave_detail.png)]
TIME_WAIT 状态,超时时间占用了 2MSL(Maximum segment lifetime) ,在 Linux 上固定是 60s
有这个状态是两方面的原因
-
一个数据报在发送途中或者响应过程中有可能成为残余的数据报,因此必须等待足够长的时间避免新的连接会收到先前连接的残余数据报,而造成状态错误。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-19RImwR0-1582258488790)(http://blog.qiusuo.im/images/duplicate-segment.png)]
-
确保被动关闭方已正常关闭
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XS74ohqW-1582258488790)(http://blog.qiusuo.im/images/last-ack.png)]
但是这样也造成了主动关闭方进入 TIME-WAIT 状态后,无论对方是否收到 ACK ,都需要等待 60s 。耗费内存、CPU及端口。为了解决这个问题,TCP协议推出了一个扩展,在 TCP Header 中可以添加2个4字节的时间戳字段,第一个是发送方的时间戳,第二个是接受方的时间戳。这样就可以避免上面两种情况。
- 防止残余报文混入新连接。得益于时间戳的存在,残余的TCP报文由于时间戳过旧,直接被抛弃。
- 当被动关闭方收到三次握手的 SYN ,得益于时间戳的存在,并不是回应一个 RST ,而是回应 FIN+ACK,而此时主动关闭方正在 SYN-SENT 状态,对于突如其来的 FIN+ACK,直接回应一个 RST ,被动关闭方接受到这个 RST 后,连接就关闭被回收了。当主动关闭方再次发起 SYN 时,就可以三次握手建立正常的连接
关于TIME_WAIT数量太多。从上面的描述我们可以知道,TIME_WAIT是个很重要的状态,但是如果在大并发的短链接下,TIME_WAIT 就会太多,这也会消耗很多系统资源。只要搜一下,你就会发现,十有八九的处理方式都是教你设置两个参数,一个叫tcp_tw_reuse,另一个叫tcp_tw_recycle的参数,这两个参数默认值都是被关闭的,后者recyle比前者resue更为激进,resue要温柔一些。另外,如果使用tcp_tw_reuse,必需设置tcp_timestamps=1,否则无效。
6.epoll的水平触发和边缘触发
epoll是实现I/O多路复用的一种方法,有水平触发(level trigger,LT,默认)和边缘触发(edge trigger,ET)两种工作模式,区别在于两种模式的返回就绪状态的时间不同。
- 水平触发
- 读:缓冲内容不为空返回读就绪
- 写:缓冲区还不满返回写就绪
- 边缘触发
- 读:
- 缓冲区由不可读变为可读
- 新数据到达,缓冲区中待读数据变多时
- 写:
- 当缓冲区由不可写变为可写
- 当有旧数据被发送走,即缓冲区中的内容变少的时候
- 读:
epoll之所以高效,是因为epoll将用户关心的文件描述符放到内核里的一个事件表中,而不是像select/poll每次调用都需要重复传入文件描述符集或事件集。比如当一个事件发生(比如说读事件),epoll无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入就绪队列的描述符集合就行了。
C/C++语言基础
1.new和malloc的区别?
new
/delete
是C++操作符,malloc
/free
是库函数new
自行计算需要空间的大小,malloc
需要指定大小new
从自由存储区分配内存,malloc
从堆上分配内存new
在分配内存时调用构造函数,delete
在释放内存时调用析构函数,malloc
只分配内存不做初始化- 在分配内存失败时,
new
抛出bac_alloc异常,malloc
则返回NULL
2.能不能用内存比较的方法比较两个struct对象
不能,struct对象由于内存对齐会有内存间隙,所以就算所以成员变量都相等,内存比较还是得到不相等的结果。
我觉得可以先memset初始化之后再使用对象,然后就可以用memcmp来对比。(有指针的话不行)
或者选择重载==运算符,一一比较所有成员变量是否相等
3.strcpy与memcpy的区别
- 复制的内容不同
- strcpy无需指定长度
4.strcpy有什么缺点
如果参数dest所指的内存空间不够大,可能会造成缓冲溢出的错误情况。
5.C如何使用cpp文件的函数?
C调C++函数:
// C++ code:
extern "C" void f(int);
void f(int i){
...}
混合调用时,在C++的.h和.cpp文件中写入
#ifdef __cplusplus
extern "C" {
#endif
//一段代码
#ifdef __cplusp