TCP/IP和网络编程面试常见问题3

接上一篇《TCP/IP和网络编程面试常见问题2》
篇幅太长,视觉疲劳了,重开一局。

时间仓促,还未细看。如有错误,欢迎指正。

(1)Linux进程间的通信方式

linux下进程间通信的几种主要手段:

  1. 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;
  2. 信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期 信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上, 该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,sigaction函数重新实现了signal函数);
  3. 报文(Message)队列(消息队列):消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点;
  4. 共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针其他通信机制运行效率较低设计的。往往与其它通信机制,如信号量结合使用, 来达到进程间的同步及互斥。
  5. 信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
  6. 套接字(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix 系统上:Linux和System V的变种都支持套接字。

(2)列出常见的信号,信号怎么处理

SIGHUP:本信号在用户终端结束时发出,通常是在终端的控制进程结束时,通知同一会话期内的各个作业,这时他们与控制终端不在关联。比如,登录linux时,系统会自动分配给登录用户一个控制终端,在这个终端运行的所有程序,包括前台和后台进程组,一般都属于同一个会话。当用户退出时,所有进程组都将收到该信号,这个信号的默认操作是终止进程。此外对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。
SIGINT:程序终止信号。当用户按下CRTL+C时通知前台进程组终止进程。
SIGQUIT:Ctrl+\控制,进程收到该信号退出时会产生core文件,类似于程序错误信号。
SIGILL:执行了非法指令。通常是因为可执行文件本身出现错误,或者数据段、堆栈溢出时也有可能产生这个信号。
SIGTRAP:由断点指令或其他陷进指令产生,由调试器使用。
SIGABRT:调用abort函数产生,将会使程序非正常结束。
SIGBUS:非法地址。包括内存地址对齐出错。比如访问一个4个字长的整数,但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法地址的非法访问触发。
SIGFPE:发生致命的算术运算错误。
SIGKILL:用来立即结束程序的运行。
SIGUSR1:留给用户使用,用户可自定义。
SIGSEGV:访问未分配给用户的内存区。或操作没有权限的区域。
SIGUSR2:留给用户使用,用户可自定义。
SIGPIPE:管道破裂信号。当对一个读进程已经运行结束的管道执行写操作时产生。
SIGALRM:时钟定时信号。由alarm函数设定的时间终止时产生。
SIGTERM:程序结束信号。shell使用kill产生该信号,当结束不了该进程,尝试使用SIGKILL信号。
SIGSTKFLT:堆栈错误。
SIGCHLD:子进程结束,父进程会收到。如果子进程结束时父进程不等待或不处理该信号,子进程会变成僵尸进程。
SIGCONT:让一个停止的进程继续执行。
SIGSTOP:停止进程执行。暂停执行。
SIGTSTP:停止运行,可以被忽略。Ctrl+z。
SIGTTIN:当后台进程需要从终端接收数据时,所有进程会收到该信号,暂停执行。
SIGTTOU:与SIGTTIN类似,但在写终端时产生。
SIGURG:套接字上出现紧急情况时产生。
SIGXCPU:超过CPU时间资源限制时产生的信号。
SIGXFSZ:当进程企图扩大文件以至于超过文件大小资源限制时产生。
SIGVTALRM:虚拟使用信号。计算的是进程占用CPU调用的时间。
SIGPROF:包括进程使用CPU的时间以及系统调用的时间。
SIGWINCH:窗口大小改变时。
SIGIO:文件描述符准备就绪,表示可以进行输入输出操作。
SIGPWR:电源失效信号。
SIGSYS:非法的系统调用。

(3)什么是守护进程?

守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。Linux的大多数服务器就是用守护进程实现的。比如,Internet服务器inetd,Web服务器httpd等。同时,守护进程完成许多系统任务。比如,作业规划进程crond,打印进程lpd等。

(4) select服务器端的实现,select与epoll的区别?

select的几大缺点:

  1. 每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
  2. 同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
  3. select支持的文件描述符数量太小了,默认是1024

epoll解决了以上缺点:

  1. 支持的FD上限是最大可以打开文件的数目;
  2. IO效率不随FD数目增加而线性下降,只会对”活跃”的socket进行操作;
  3. epoll在epoll_ctl函数中,每次注册新的事件到epoll句柄中时,会把所有的fd拷贝进内核,而不是在epoll_wait的时候重复拷贝。epoll保证了每个fd在整个过程中只会拷贝一次。
  4. 使用mmap加速内核与用户空间的消息传递.

(5)connect会阻塞,怎么解决?

非阻塞
步骤1: 设置非阻塞,启动连接
实现非阻塞 connect ,首先用Fcntl()函数把 sockfd 设置成非阻塞的。这样调用connect 可以立刻返回,根据返回值和 errno 处理三种情况:
(1) 如果返回 0,表示 connect 成功。
(2) 如果返回值小于 0, errno 为 EINPROGRESS, 表示连接
建立已经启动但是尚未完成。这是期望的结果,不是真正的错误。
(3) 如果返回值小于0,errno 不是 EINPROGRESS,则连接出错了。
步骤2:判断可读和可写
然后把 sockfd 加入 select 的读写监听集合,通过 select 判断 sockfd 是否可写,
(1) 如果连接建立好了,那么 sockfd 是可写的
(2) 如果连接发生错误,sockfd 也是可读和可写的。
步骤3:使用 getsockopt 函数检查错误
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &len)
在 sockfd 都是可读和可写的情况下,我们使用 getsockopt 来检查连接是否出错。
步骤4:重新将套接字设置为阻塞
用信号设置超时
定义信号处理函数:

sigset(SIGALRM, u_alarm_handler);
alarm(2);
code = connect(socket_fd, (struct sockaddr*)&socket_st, sizeof(struct sockaddr_in));
alarm(0);
sigrelse(SIGALRM);

首先定义一个中断信号处理函数u_alarm_handler,用于超时后的报警处理,然后定义一个2秒的定时器,执行connect,当系统connect成功,则系统正常执行下去;如果connect不成功阻塞在这里,则超过定义的2秒后,系统会产生一个信号,触发执行u_alarm_handler函数,当执行完u_alarm_handler后,程序将继续从connect的下面一行执行下去。
其中,处理函数可以如下定义,也可以加入更多的错误处理。

void u_alarm_handler()
{
}

(6)TCP的connect函数与UDP的connect函数区别?

在网络编程中,connect函数通常用于客户端建立tcp连接。tcp连接的建立实际上就是三次“握手”的过程。
udp协议提供的是面向非连接的服务,通信双方不需要建立连接。一方只需要建立好套接字,并显式或由系统绑定地址和端口号后就可以发送/接收数据包。和tcp不同的是,使用udp协议的数据报套接字(SOCK_DGRAM)并不限定唯一的通信方。既可以发送(sendto)数据给任意的接受方,也可以从任意的发送方接收(recvfrom)数据。
如果希望为一个数据报套接字指定唯一的通信方时,可以使用connect来实现这一功能。需要注意的是,在数据报套接字上使用connect并不是建立连接,不存在“握手”的过程。仅仅是为这个套接字指定一个通信方,一旦指定了对方的地址,就可以通过send/recv来发送/接收数据了。而且可以在这个数据报套接字上多次调用connect函数来指定不同的通信方。
在udp中使用connect的方法和tcp中类似,只需在创建套接字时,把套接字的类型由SOCK_STREAM换成SOCK_DGRAM即可。

(7)socket什么情况下可读?

套接字准备好读的条件:

a)该套接字接受缓冲区中的数据字节数大于等于套接字接受缓冲区低水位标记的当前大小。对这样的套接字执行读操作不会阻塞并将返回一个大于0的值(也就是返回准备好读入的数据)。我们可以使用SO_RCVLOWAT套接字选项设置该套接字的低水位标记。对于tcp和udp套接字而言,其默认值为1。
b)该套接字的读半部关闭(也就是接受了FIN的tcp连接)。对这样的套接字的读操作将不阻塞并返回0.(也就是返回EOF)
c)该套接字是一个监听套接字且已完成的连接数不为0。对这样的套接字的accept通常不阻塞。
d)其上有一个套接字错误待处理。对这样的套接字的读操作将不阻塞并返回-1(也就是返回一个错误),同时把errno设置成确切的错误条件。这样待处理错误(pending error)也可以通过指定SO_ERROR套接字选项调用getsockopt获取并清除。

套接字准备好写的条件:

a)该套接字发送缓冲区中的可用空间字节数大于等于套接字发送缓冲区低水位标记的当前大小,并且或者该套接字已连接,或者该套接字不需要连接(如udp套接字)。这意味着如果我们把这样的套接字设置成非阻塞,写操作将不阻塞并返回一个正值(例如由传输层接受的字节数)。我们可以使用SO_SNDLOWAT套接字选项来设置该套接字的低水位标记。对于tcp和udp而言,其默认值通常为2048。
b)该连接的写半部关闭。对这样的套接字的写操作将产生SIGPIPE信号。
c) 使用非阻塞connect的套接字已建立连接,或者connect已经以失败告终。
d) 其上有一个套接字错误待处理。对这样的套接字的写操作将不阻塞并返回-1(也就是返回一个错误),同时把errno设置成确切的错误条件。这些待处理的错误也可以通过指定SO_ERROR套接字选项调用getsockopt获取并清除。

参考信息
https://blog.csdn.net/u013354486/article/details/80588916
https://blog.csdn.net/E_kunt/article/details/52623614
http://blog.csdn.net/qq_25827845/article/details/66975129
https://blog.csdn.net/qq_40086556/article/details/82017916
https://blog.csdn.net/qq_38238296/article/details/87869753

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值