# myTinyWebServer **Repository Path**: sun-hash/myTinyWebServer ## Basic Information - **Project Name**: myTinyWebServer - **Description**: 服务器demo - **Primary Language**: C++ - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-08-06 - **Last Updated**: 2021-09-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 一、已经实现的功能 1、在超时时间触发是,执行回调函数的同时需要删除已经使用过的节点。 2、TODO 半同步半反应堆模型不请求能处理带状态的 ### 二、多线程服务器项目记录 1、构建对象时,使用构造函数+init()组合,防止线程不安全,主要表现在不要将this指针暴露在构造函数中, ``` c++ head->cb_func(); tmp = head; head = head->next; delete tmp; ``` 2、要在静态函数中使用类的动态成员,只有两个办法 ①通过类的静态对象来调用。比如单体模式中,静态函数可以通过类的全局唯一实例来访问动态成员函数。 ②将类的对象作为参数传递给该静态函数,然后在静态函数中引用这个对象,并调用其动态方法 ``` c++ #include int sem_init(sem_t *sem, int pshared, unsigned int value); 功能: 创建一个信号量并初始化它的值。一个无名信号量在被使用前必须先初始化。 参数: sem:信号量的地址。 pshared:等于 0,信号量在线程间共享(常用);不等于0,信号量在进程间共享。 value:信号量的初始值。 int sem_destroy(sem_t *sem); 功能: 删除 sem 标识的信号量。 参数: sem:信号量地址。 返回值: 成功:0 失败: - 1 int sem_wait(sem_t *sem); 功能: 将信号量的值减 1。操作前,先检查信号量(sem)的值是否为 0,若信号量为 0,此函数会阻塞,直到信号量大于 0 时才进行减 1 操作。 参数: sem:信号量的地址。 返回值: 成功:0 失败: - 1 ​ int sem_post(sem_t *sem); 功能: 将信号量的值加 1 并发出信号唤醒等待线程(sem_wait())。 参数: sem:信号量的地址。 返回值: 成功:0 失败:-1 ``` 3、通过迭代器得到指针 ``` c++ vector a; int * ger() { return &*a.begin(); } ``` 4、Vscode折叠快捷键ctrl+k,ctrl+0(all),ctrl+k,ctrl+j(展开all), ctrl+k,ctrl+[ ] (展开,关闭迭代) 5、三个buff,内核buffer,应用层buffer,socketbuffer. 先明确一个概念:每个TCP socket在内核中都有一个发送缓冲区和一个接收缓冲区,TCP的全双工的工作模式以及TCP的滑动窗口便是依赖于这两个独立的buffer以及此buffer的填充状态。接收缓冲区把数据缓存入内核,应用进程一直没有调用read进行读取的话,此数据会一直缓存在相应 socket的接收缓冲区内。再啰嗦一点,不管进程是否读取socket,对端发来的数据都会经由内核接收并且缓存到socket的内核接收缓冲区之中。 read所做的工作,就是把内核缓冲区中的数据拷贝到应用层用户的buffer里面,仅此而已。进程调用send发送的数据的时候,最简单情况(也是一般情况),将数据拷贝进入socket的内核发送缓冲区之中,然后send便会在上层返回。换句话说,send返回之时,数据不一定会发送到对端去(和 write写文件有点类似),send仅仅是把应用层buffer的数据拷贝进socket的内核发送buffer中。后续我会专门用一篇文章介绍 read和send所关联的内核动作。每个UDP socket都有一个接收缓冲区,没有发送缓冲区,从概念上来说就是只要有数据就发,不管对方是否可以正确接收,所以不缓冲,不需要发送缓冲区。 接收缓冲区被TCP和UDP用来缓存网络上来的数据,一直保存到应用进程读走为止。对于TCP,如果应用进程一直没有读取,buffer满了之后,发生的动作是:通知对端TCP协议中的窗口关闭。这个便是滑动窗口的实现。保证TCP套接口接收缓冲区不会溢出,从而保证了TCP是可靠传输。因为对方不允许发出超过所通告窗口大小的数据。 这就是TCP的流量控制,如果对方无视窗口大小而发出了超过窗口大小的数据,则接收方TCP将丢弃它。 UDP:当套接口接收缓冲区满时,新来的数据报无法进入接收缓冲区,此数据报就被丢弃。UDP是没有流量控制的;快的发送者可以很容易地就淹没慢的接收者,导致接收方的UDP丢弃数据报。 以上便是TCP可靠,UDP不可靠的实现 6、bzero可以给结构体清零,memset不能 7、socketpair 双向套接字管道,参数设置为 PF_UNIX 8、添加信号的流程 ``` c++ void webServer::addSig(int sig) { struct sigaction sa1; memset(&sa1,'\0', sizeof(sa1)); //TODOmemeset好像也能清空结构体? sa1.sa_handler = signalHandler1; sa1.sa_flags|=SA_RESTART; sigfillset(&sa1.sa_mask); } // 回调函数不能是类成员函数 //TODO ``` 9、设置非阻塞的流程 ```c++ int setNoBlock(int fd) { int old_option = fcntl(fd, F_GETFL); int new_option = old_option | O_NONBLOCK; fcntl(fd, F_SETFL, new_option); return old_option; } ``` 10、写if不写else要记得return 11、case后面记得写break; ###