网络编程-HTTP

发布于:2025-09-11 ⋅ 阅读:(16) ⋅ 点赞:(0)

API请求包含内容(参数常常有用户名、密码、调用接口名称、接口需要的参数):协议://地址:端口/api?参数1=值1&参数2=值2

HTTP通信步骤:客户端连接到web服务器、按照请求报文格式(请求行:get还是post、请求头部:域名、浏览器、接受类型、保持tcp连接)发送请求报文、web服务端接受请求并返回http响应(状态行:HTTP/1.1 200 OK、头部信息:服务端名称、响应文件长度、响应文件类型)、web服务端释放连接TCP连接、客户端解析web服务端的响应分析html内容

服务端模拟程序:创建socket、绑定ip端口通信类型到socket、设置socket状态为可监听、阻塞受理客户端连接请求、清空buffer接受客户端内容、打印buffer内容、拼接响应报文(状态行:状态码、状态描述符;响应报文头部:字段(正文长度)、字段值;响应报文正文:xxx)、发送状态行和头部信息、发送正文信息(按照&划分解析get请求参数、打印字符串、连接数据库、判断用户名和密码的合法性、准备命令行、prepare查询语句:字面量和拼接字段符构成xml样式的结果、绑定结果集和字段条件、执行语句、写xml前缀、while中next,循环写结果集的一组字段、写xml后缀)、关闭监听socket、关闭recv的socket

客户端模拟程序:创建socket、绑定socket并连接、拼接http协议的请求报文(请求行:get方法、url、协议版本、回车换行、请求头部:域名、端口、请求头部结束符)、发送请求报文、接受网站回应、打印回应内容、关闭socket

判断响应报文结束的三种方法:响应报文的头部的报文长度字段、网络是否断开、是否采用分块传输

接口表中不同接口:拥有接口名字段、对应sql语句字段、bindout字段(结果集)、bindin字段(查询条件)不同用户拥有调用不同接口的权限,不同接口可以按照不同条件,查询不同表的不同字段

webserver函数:main函数:屏蔽所有其他中断、设置kill中断和ctrl+c中断、打开日志、创建接受线程、工作线程1、工作线程2、工作线程3、发送线程,while中循环休眠

webserver函数:接受线程函数:调用initsever函数初始化端口并返回的socket、加入epoll并设置为读事件(作用是,epollwait在等待下一个listen事件时处于阻塞状态,当退出信号到来时,可以避免使用全局变量,在exit函数中,向管道写入端写入数据,改变管道读取端状态,从而触发epoll事件,立即通知工作线程和发送线程退出)、设置存放事件的数组、while死循环中:epoll_wait阻塞监听最多10个事件、有事件发生进入for循环(发生事件个数为累积条件):如果是监听事件、用accept从请求队列中接受一个事件、为此事件设置非阻塞方便后续的read和write为非阻塞、以此文件描述符为键的map中添加新的值(ip:通过inet_ntoa转换二进制为字符串的、端口等信息的结构体)、设置此客户端连接的socket并添加到epoll中设置为读事件、continue退出本次的事件循环进行下一次事件循环、如果是管道事件、原子变量设置为true(工作线程被唤醒后会检查原子变量、发送线程被管道唤醒后会检查原子变量)、 线程唤醒工作线程、写管道通知发送线程 、如果recv的返回值小于0说明是退出信号那么关闭socket连接、状态机(键值对、键为客户端socket,值为IP地址、最后活动时间、接收缓冲区、发送缓冲区 )中删除客户端、continue进行下一次的循环、否则为正常接收到数据、使用状态机中接受缓冲区的apend追加内容,使用状态机中接受缓冲区的compare比较倒数第四个字符后四个字符和\r\n\r\n的对比,使用inrq函数将完整的请求报文入队,清空当前状态机对应客户端的接受缓冲区、若没有结束,且多次添加后的总字节数>1000则关闭客户端连接,状态机中删除客户端、每次有请求来都要更新客户端时间

webserver函数:初始化服务端监听并端口:创建socket、设置可绑定timewait中的tcp、设置网络参数、绑定网络参数到socket、监听socket、设置监听的socket为非阻塞方便recept为非阻塞、创建epoll句柄、设置epoll属性为读时间并关联到listen句柄、将管道读取端(有数据到达写入端时,读取端状态发生变化,触发事件)

webserver函数:请求报文入队函数inrq:将sock和message捆绑后用智能指针指向、申请加锁(保护后面指针入队和通知工作线程两个步骤)、将智能指针放入队列、使用notify_one通知工作线程

webserver函数:工作线程函数workfunc:连接数据库、设置智能指针、设置互斥锁作用域、作用域内设置互斥锁、队列为空进入循环,循环中使用wait释放锁(给转移到队列过程加锁时机)线程休眠(下次唤醒恢复加锁成功后直接从此开始执行)、唤醒后判断是否为线程退出标志、循环外队列中有数据了就出队一个元素(出了作用域就解锁成功)、构建响应行头&响应行&拼接响应内容、调用insq将响应报文放入队列

webserver函数:查询数据库构建响应报文函数bizmain:解析请求报文、验证用户身份、判断用户使用接口权限、获取接口对应的sql语句&sql语句中的字段&sql语句中的条件参数、prepare带有占位符的查询语句、分割invalue后将invalue放入数组中绑定到占位符作查询条件(invalue是查询字段的值)、分割colstr后将colstr字段放入colvalue数组绑定到结果集(查询结果的各个字段值放入其中)、若执行失败用stmt的rc和message作为响应报文、否则用0和ok构建回应头部、sendbuf拼接xml头部、循环中stmt.next一下sendbuf拼接<字段名>字段值<字段名>、xml结束标签

webserver函数:响应报文入队函数insq:使用智能指针指向对应的sock和响应报文、申请加锁(对智能指针入队的保护,作用域内都收到锁的保护)、指针入队、用通道的形式向发送线程发送信号(向写入端写入,那么读取端状态发生变化,阻塞在epoll_wait的发送线程被唤醒)

webserver函数:发送线程函数sendfunc:创建epoll句柄&声明epoll数据结构、将管道放入事件设置为读事件、事件循环中:阻塞监控最多10个事件、遍历已发送事件、如果发生事件是管道事件:(先检查全局退出标志、读取管道数据恢复读取端状态、设置智能指针,申请加锁、while队列不为空:出队一个元素(智能指针)、出队的智能指针作为状态机的键盘找到对应的值sendbuffer并将ptr指向的message添加到发送缓冲区sendbuffer、将客户端写事件放入epoll中,continue监视下一次事件、如果发生的是客户端写事件(用send发送客户端socket&状态机中该socket对应的sendbuffer和length、用状态机删除该socket对应的sendbuffer中已经发送的written个字节、若clientmap的socket的sendbuffer没有数据,就将socket的写事件从队列中删除)

webserver函数:总进程退出函数exit:忽略其他信号(防止在退出过程中有其他信号打断)、通知接收线程退出、休眠500ms后总程序退出

webserver函数:从请求报文中获取字段值函数getvalue:找到字符串中name的起始位置、指针到字符串末尾(npos)即没有找到就退出、找到字符串中&的起始位置作为endp、没找到说明最后一个参数就判断空格(空格作为结束符)并将位置给endp,要是连空格也没找到说明请求报文格式有问题就返回false,从请求报文字符串中截取字符串(起始位置为startp:可以调用apend+字段名长度+1(<字段名>的>要略过)、计算字段值长度:结尾-开头-字段名长度-包含等号的1)

ptr可以指向sock和对应的message:

clienttmap中有sendbuffer和recvbuffer:


网站公告

今日签到

点亮在社区的每一天
去签到