常见网络编程面试题答案征集与面试题收集

hui12345685 2011-09-04 10:57:08
1:tcp和udp的区别
2:流量控制和拥塞控制的实现机制
3:滑动窗口的实现机制
4:多线程如何同步。
5:进程间通讯的方式有哪些,各有什么优缺点
6:tcp连接建立的时候3次握手的具体过程,以及其中的每一步是为什么
7:tcp断开连接的具体过程,其中每一步是为什么那么做
8:tcp建立连接和断开连接的各种过程中的状态转换细节
9:epool与select的区别
10:epool中et和lt的区别与实现原理
11:写一个server程序需要注意哪些问题
12:项目中遇到的难题,你是如何解决的

以上是面试中遇到的一些面试题,征集一下大家的答案,同时如果大家有什么好的面试题,也可以发上来一块讨论。本来想给200或者300分的,但上限只能给100了,请高手们见谅了。
...全文
6681 29 打赏 收藏 转发到动态 举报
写回复
用AI写文章
29 条回复
切换为时间正序
请发表友善的回复…
发表回复
cl1_1_1_1 2013-08-06
  • 打赏
  • 举报
回复
顶起
xunlei1211 2013-07-15
  • 打赏
  • 举报
回复
不错!mark
xiaosa531 2013-07-03
  • 打赏
  • 举报
回复
顶起,楼主,再回答下其他的问题。
满衣兄 2011-09-19
  • 打赏
  • 举报
回复
Ol_lO 2011-09-19
  • 打赏
  • 举报
回复
mark
dldx_062 2011-09-19
  • 打赏
  • 举报
回复
楼主 这么辛苦把问题和答案都贴出来,沉下去也太可惜了,顶起
就想叫yoko 2011-09-19
  • 打赏
  • 举报
回复
mark
冻结 2011-09-19
  • 打赏
  • 举报
回复
每个题都能答两句,每个问题都答不全。
epoll这样才顺眼!

unix 网络编程
tcp/ip 详解
lin52na 2011-09-19
  • 打赏
  • 举报
回复
被这个 “epool中et和lt的区别与实现原理”问倒过。。。
koalapheonix 2011-09-19
  • 打赏
  • 举报
回复
我也被time_wait问倒过,哎....
hui12345685 2011-09-18
  • 打赏
  • 举报
回复
4:多线程如何同步
在这里简单说一下linux多线程同步的方法吧(win上有一定的差别,也有一定的累似)
1:线程数据,每个线程数据创建一个键,它和这个键相关联,在各个线程里,都使用这个键来指代线程数据,但在不同的线程里,这个键代表的数据是不同的,在同一个线程里,它代表同样的数据内容。以此来达到线程安全的目的。
2:互斥锁,就是在各个线程要使用的一些公共数据之前加锁,使用之后释放锁,这个是非常常用的线程安全控制的方法,而频繁的加解锁也对效率有一定的影响。
3:条件变量,而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其它的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。一般说来,条件变量被用来进行线程间的同步。
4:信号量,信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。当公共资源增加时,调用函数sem_post()增加信号量。只有当信号量值大于0时,才能使用公共资源,使用后,函数sem_wait()减少信号量。函数sem_trywait()和函数pthread_ mutex_trylock()起同样的作用,它是函数sem_wait()的非阻塞版本

另外pthread_join也可以等待一个线程的终止。可能还有一些其他我暂时没有想到的方法,欢迎补充
hui12345685 2011-09-17
  • 打赏
  • 举报
回复
既然没有人来回答,这些问题我自己慢慢来回答吧,不过大家总应该顶起来吧,要不然100分给谁呢
epool与select的区别:
select在一个进程中打开的最大fd是有限制的,由FD_SETSIZE设置,默认值是2048。不过 epoll则没有这个限制,它所支持的fd上限是最大可以打开文件的数目,这个数字一般远大于2048,一般来说内存越大,fd上限越大,1G内存都能达到大约10w左右。

select的轮询机制是系统会去查找每个fd是否数据已准备好,当fd很多的时候,效率当然就直线下降了,epoll采用基于事件的通知方式,一旦某个fd数据就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,而不需要不断的去轮询查找就绪的描述符,这就是epool高效最本质的原因。

无论是select还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的,而select则做了不必要的拷贝
Defonds 2011-09-17
  • 打赏
  • 举报
回复
have a mark
hui12345685 2011-09-17
  • 打赏
  • 举报
回复
今天就答这么多了,大家顶起来啊
hui12345685 2011-09-17
  • 打赏
  • 举报
回复
进程间通信主要包括管道, 系统IPC(包括消息队列,信号量,共享存储), socket.

管道包括三种:1)普通管道PIPE, 通常有种限制,一是半双工,只能单向传输;二是只能在父子进程间使用. 2)流管道s_pipe: 去除了第一种限制,可以双向传输. 3)命名管道:name_pipe, 去除了第二种限制,可以在许多并不相关的进程之间进行通讯.

系统IPC的三种方式类同,都是使用了内核里的标识符来识别

管道: 优点是所有的UNIX实现都支持, 并且在最后一个访问管道的进程终止后,管道就被完全删除;缺陷是管道只允许单向传输或者用于父子进程之间

系统IPC: 优点是功能强大,能在毫不相关进程之间进行通讯; 缺陷是关键字KEY_T使用了内核标识,占用了内核资源,而且只能被显式删除,而且不能使用SOCKET的一些机制,例如select,epoll等.

socket可以跨网络通讯,其他进程间通讯的方式都不可以,只能是本机进程通讯。
hui12345685 2011-09-17
  • 打赏
  • 举报
回复
10:epool中et和lt的区别与实现原理
LT:水平触发,效率会低于ET触发,尤其在大并发,大流量的情况下。但是LT对代码编写要求比较低,不容易出现问题。LT模式服务编写上的表现是:只要有数据没有被获取,内核就不断通知你,因此不用担心事件丢失的情况。
ET:边缘触发,效率非常高,在并发,大流量的情况下,会比LT少很多epoll的系统调用,因此效率高。但是对编程要求高,需要细致的处理每个请求,否则容易发生丢失事件的情况。

另一点区别就是设为ET模式的文件句柄必须是非阻塞的

附一个例子:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <sys/resource.h>
#define MAXBUF 1024
#define MAXEPOLLSIZE 10000
/*
setnonblocking - 设置句柄为非阻塞方式
*/
int setnonblocking(int sockfd)
{
if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1)
{
return -1;
}
return 0;
}
/*
handle_message - 处理每个 socket 上的消息收发
*/
int handle_message(int new_fd)
{
char buf[MAXBUF + 1];
int len;
/* 开始处理每个新连接上的数据收发 */
bzero(buf, MAXBUF + 1);
/* 接收客户端的消息 */
len = recv(new_fd, buf, MAXBUF, 0);
if (len > 0)
{
printf("%d接收消息成功:'%s',共%d个字节的数据\n",
new_fd, buf, len);
}
else
{
if (len < 0)
printf
("消息接收失败!错误代码是%d,错误信息是'%s'\n",
errno, strerror(errno));
close(new_fd);
return -1;
}
/* 处理每个新连接上的数据收发结束 */
return len;
}
int main(int argc, char **argv)
{
int listener, new_fd, kdpfd, nfds, n, ret, curfds;
socklen_t len;
struct sockaddr_in my_addr, their_addr;
unsigned int myport, lisnum;
struct epoll_event ev;
struct epoll_event events[MAXEPOLLSIZE];
struct rlimit rt;
myport = 5000;
lisnum = 2;
/* 设置每个进程允许打开的最大文件数 */
rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;
if (setrlimit(RLIMIT_NOFILE, &rt) == -1)
{
perror("setrlimit");
exit(1);
}
else
{
printf("设置系统资源参数成功!\n");
}
/* 开启 socket 监听 */
if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(1);
}
else
{
printf("socket 创建成功!\n");
}
setnonblocking(listener);
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = PF_INET;
my_addr.sin_port = htons(myport);
my_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(listener, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1)
{
perror("bind");
exit(1);
}
else
{
printf("IP 地址和端口绑定成功\n");
}
if (listen(listener, lisnum) == -1)
{
perror("listen");
exit(1);
}
else
{
printf("开启服务成功!\n");
}
/* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */
kdpfd = epoll_create(MAXEPOLLSIZE);
len = sizeof(struct sockaddr_in);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = listener;
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listener, &ev) < 0)
{
fprintf(stderr, "epoll set insertion error: fd=%d\n", listener);
return -1;
}
else
{
printf("监听 socket 加入 epoll 成功!\n");
}
curfds = 1;
while (1)
{
/* 等待有事件发生 */
nfds = epoll_wait(kdpfd, events, curfds, -1);
if (nfds == -1)
{
perror("epoll_wait");
break;
}
/* 处理所有事件 */
for (n = 0; n < nfds; ++n)
{
if (events[n].data.fd == listener)
{
new_fd = accept(listener, (struct sockaddr *) &their_addr,&len);
if (new_fd < 0)
{
perror("accept");
continue;
}
else
{
printf("有连接来自于: %d:%d, 分配的 socket 为:%d\n",
inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);
}
setnonblocking(new_fd);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = new_fd;
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, new_fd, &ev) < 0)
{
fprintf(stderr, "把 socket '%d' 加入 epoll 失败!%s\n",
new_fd, strerror(errno));
return -1;
}
curfds++;
}
else
{
ret = handle_message(events[n].data.fd);
if (ret < 1 && errno != 11)
{
epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd,&ev);
curfds--;
}
}
}
}
close(listener);
return 0;
}
hui12345685 2011-09-11
  • 打赏
  • 举报
回复
最近太忙了,没什么时间来。帖子都快沉底了
我说一下6和7吧,8的答案unix网络编程卷1上有答案,tcp、ip详解上估计也有
6:建立连接采用的3次握手协议,具体是指:
第一次握手是客户端connect连接到server,server accept client的请求之后,向client端发送一个消息,相当于说我都准备好了,你连接上我了,这是第二次握手,第3次握手就是client向server发送的,就是对第二次握手消息的确认。之后client和server就开始通讯了。
7:断开连接的4次握手,具体如下:
断开连接的一端发送close请求是第一次握手,另外一端接收到断开连接的请求之后需要对close进行确认,发送一个消息,这是第二次握手,发送了确认消息之后还要向对端发送close消息,要关闭对对端的连接,这是第3次握手,而在最初发送断开连接的一端接收到消息之后,进入到一个很重要的状态time_wait状态,这个状态也是面试官经常问道的问题,最后一次握手是最初发送断开连接的一端接收到消息之后。对消息的确认。
以上属于个人理解,请大家补充答案和纠正。
smilenot 2011-09-04
  • 打赏
  • 举报
回复
题目比较难,只有个别题目会答,而且都是大家都知道的
qq120848369 2011-09-04
  • 打赏
  • 举报
回复
背答案没用的,就问你开发过什么,谈谈经验。

答案:没有。

jackyjkchen 2011-09-04
  • 打赏
  • 举报
回复
问题好多,虽然分多,但十几个问题还是让人觉得楼主太贪了……

大家一人回答1个吧

1.tcp和udp的区别
tcp有连接,有验证重发机制,能保证通信可靠性
udp无连接,存在丢包、错包、乱序现象,但开销小
加载更多回复(7)

64,701

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧