大纲
-
线程的创建和使用(pthread)
-
IO多路复用:select
-
IO多路复用:poll
-
IO多路复用:epoll
附加的知识: -
#if、#elif、#else 和 #endif 指令详解 (C/C++)
-
网络调试助手
网络:主机通信的基石
TCP:端对端通信
只用TCP的话,连接两个客户端,为什么都可以连接,但是第二个无法接收
listen处于listen状态,但是三次握手是在协议栈中完成的,不属于任何一个API
怎么解决,线程
pthread
可以解决多次连接的问题,每次创建一个线程来处理
IO多路复用:用来解决多个线程,知道哪个线程来响应的问题
select
- 在一请求一线程的情况下,select突破不了C10K,最多一万个线程
- select可以做到1024个fd的管理,多做几个select可以突破C10K
- select每次都需要cv所有的fd,所以性能有提升的地方
struct fd_set ,可以理解为一个集合,实际上是一个位图,每一个特定为来标志相应大小文件描述符,这个集合中存放的是文件描述符(file descriptor),即文件句柄(也就是位图上的每一位都能与一个打开的文件句柄(文件描述符)建立联系,这个工作由程序员来完成),这可以是我们所说的普通意义的文件,当然Unix下任何设备、管道、FIFO等都是文件形式,全部包括在内,所以毫无疑问一个socket就是一个文件,socket句柄就是一个文件描述符。
程序员通过操作4类宏,来完成最fd_set的操作:
(1)、FD_ZERO(fd_set *) 清空一个文件描述符集合;(2)、FD_SET(int ,fd_set *)将一个文件描述符添加到一个指定的文件描述符集合中;
(3)、FD_CLR(int ,fd_set*) 将一个给定的文件描述符从集合中删除;
(4)、FD_ISSET(int ,fd_set* )检查集合中指定的文件描述符是否可以读写。
poll
和select差不多,个人感觉主要是在存储fd的形式上有所不同,poll用一个结构体存储一个fd的三个状态,而select是用三个fd_set(实质是long)来存储三种不同状态。
对于检测命令
if(fds[i].revents & POLLIN)
epoll
性能相比于select/poll 提升了许多,是现在常用的多路复用处理方式
epoll中的特殊结构为epoll_event
struct epoll_event
{undefined
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
} __attribute__ ((__packed__));
typedef union epoll_data
{undefined
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
reactor
struct nitem; // 存储一个socket事件的属性
struct itemblock; // 存储指向一个事件的指针和下一个事件块的指针
struct reactor; // 存储一个epoll对象和他对应的事件块的指针
struct reactor* instance = NULL;
struct reactor* getInstance(void);// 单例模式,创建一个reactor事件
int nreactor_set_event(int fd, NCALLBACK cb, int event, void *arg); //
int nreactor_del_event(int fd, MACLLBACK cb, int event, void *arg); //
int write_callback(int fd, int event, void *arg); //
int read_callback(int fd, int event, void *arg); //
int accept_callback(int fd, int event, void *arg); //
int init_server(int port); //socket的封装
int init_reactor(struct reactor *r);
// 作用是创建一个epoll对象并且给他申请内存空间
int reactor_loop(int listenfd); //
int main();
在运行reactor的时候,出现 了一个Segmentation fault
这个说明指针的内存分配出现了问题。