【TinyWebServer】13踩坑和面试题

踩坑

在此项目中遇到的一些比较有意义的问题

大文件传输

先看下游双书上发送逻辑这块的代码,发送数据只调用了writev函数,并对其返回值是否异常做了处理。

bool http_conn::write()
{
	int temp = 0;
	int byte_have_send = 0;   
	int byte_to_send = m_write_idx;  

	if(byte_to_send == 0)
	{
		modfd(m_epollfd,m_sockfd,EPOLLIN);
		init();
		return true;
	}

	while(1)
	{
		temp = writev(m_sockfd,m_iv,m_iv_count);
		if(temp <= -1)
		{
			if(errno == EAGAIN)
			{
				modfd(m_epollfd,m_sockfd,EPOLLOUT);
				return true;
			}
			unmap();
			return false;
		}
		byte_to_send -= temp;
		byte_have_send += temp;
		if(byte_to_send <= bytes_have_send)
		{
			unmap();
			if(m_linger)
			{
				init();
				modfd(m_epollfd,m_sockfd,EPOLLIN);
				return true;
			}
			else
			{
				modfd(m_epollfd,m_sockfd,EPOLLIN);
				return false;
			}
		}
	}
}

在实际测试中发现,当请求小文件,也就是调用一次writev函数就可以将数据全部发送出去的时候,不会报错,此时不会再次进入while循环。

一旦请求服务器文件较大文件时,需要多次调用writev函数,便会出现问题,不是文件显示不全,就是无法显示。

对数据传输过程分析后,定位到writev的m_iv结构体成员有问题,每次传输后不会自动偏移文件指针和传输长度,还会按照原有指针和原有长度发送数据。

根据前面的基础API分析,我们知道writev以顺序iov[0],iov[1]至iov[iovcnt-1]从缓冲区中聚集输出数据。项目中,申请了2个iov,其中iov[0]为存储报文状态行的缓冲区,iov[1]指向资源文件指针。

对上述代码做了修改如下:

  • 由于报文消息报头较小,第一次传输后,需要更新m_iv[1].iov_base和iov_len,m_iv[0].iov_len置成0,只传输文件,不用传输响应消息头
  • 每次传输后都要更新下次传输的文件起始位置和长度

更新后,大文件传输得到了解决。

bool http_conn::write()
{
    int temp = 0;

    int newadd = 0;

    if (bytes_to_send == 0)
    {
        modfd(m_epollfd, m_sockfd, EPOLLIN, m_TRIGMode);
        init();
        return true;
    }

    while (1)
    {
        temp = writev(m_sockfd, m_iv, m_iv_count);

        if (temp >= 0)
        {
            bytes_have_send += temp;
            newadd = bytes_have_send - m_write_idx;
        }
        else
        {
            if (errno == EAGAIN)
            {
                if (bytes_have_send >= m_iv[0].iov_len)
                {
                    m_iv[0].iov_len = 0;
                    m_iv[1].iov_base = m_file_address + newadd;
                    m_iv[1].iov_len = bytes_to_send;
                }
                else
                {
                    m_iv[0].iov_base = m_write_buf + bytes_have_send;
                    m_iv[0].iov_len = m_iv[0].iov_len - bytes_have_send;
                }
                modfd(m_epollfd, m_sockfd, EPOLLOUT, m_TRIGMode);
                return true;
            }
            unmap();
            return false;
        }
        bytes_to_send -= temp;
        if (bytes_to_send <= 0)

        {
            unmap();
            modfd(m_epollfd, m_sockfd, EPOLLIN, m_TRIGMode);

            if (m_linger)
            {
                init();
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}

面试点

包括项目介绍,线程池相关,并发模型相关,HTTP报文解析相关,定时器相关,日志相关,压测相关,综合能力等。

项目介绍

  • 为什么要做这样一个项目?
  • 介绍下你的项目

线程池相关

  • 手写线程池
  • 线程的同步机制有哪些?
  • 线程池中的工作线程是一直等待吗?
  • 你的线程池工作线程处理完一个任务后的状态是什么?
  • 如果同时1000个客户端进行访问请求,线程数不多,怎么能及时响应处理每一个呢?
  • 如果一个客户请求需要占用线程很久的时间,会不会影响接下来的客户请求呢,有什么好的策略呢?

并发模型相关

  • 简单说一下服务器使用的并发模型?
  • reactor、proactor、主从reactor模型的区别?
  • 你用了epoll,说一下为什么用epoll,还有其他复用方式吗?区别是什么?

HTTP报文解析相关

  • 用了状态机啊,为什么要用状态机?
  • 状态机的转移图画一下
  • https协议为什么安全?
  • https的ssl连接过程
  • GET和POST的区别

数据库登录注册相关

  • 登录说一下?
  • 你这个保存状态了吗?如果要保存,你会怎么做?(cookie和session)
  • 登录中的用户名和密码你是load到本地,然后使用map匹配的,如果有10亿数据,即使load到本地后hash,也是很耗时的,你要怎么优化?
  • 用的mysql啊,redis了解吗?用过吗?

定时器相关

  • 为什么要用定时器?
  • 说一下定时器的工作原理
  • 双向链表啊,删除和添加的时间复杂度说一下?还可以优化吗?
  • 最小堆优化?说一下时间复杂度和工作原理

日志相关

  • 说下你的日志系统的运行机制?
  • 为什么要异步?和同步的区别是什么?
  • 现在你要监控一台服务器的状态,输出监控日志,请问如何将该日志分发到不同的机器上?(消息队列)

压测相关

  • 服务器并发量测试过吗?怎么测试的?
  • webbench是什么?介绍一下原理
  • 测试的时候有没有遇到问题?

综合能力

  • 你的项目解决了哪些其他同类项目没有解决的问题?
  • 说一下前端发送请求后,服务器处理的过程,中间涉及哪些协议?

转载文章:

最新版Web服务器项目详解 - 13 踩坑和面试题 (qq.com)

posted @ 2023-10-06 21:14  -zx-  阅读(94)  评论(0编辑  收藏  举报