一、计算机网络基础 1、协议 通信双方需要遵循的规则。
2、TCP/IP协议
3、协议格式(==了解==) 在不同的层,都会有相应的包头,每个包头都会有对应的格式,这个作为了解,如果给出头的图,可以将其封装起来就可以了。
4、TCP协议(==重要==) TCP协议是一个传输层 的协议、面向连接 的协议、可靠 的协议、全双工 的协议、字节流的协议、进行流量控制的协议 。
三次握手(建立连接)
四次挥手(断开连接)
2MSL
5、状态迁移图(==重要==) 一共有11中状态。
2MSL时间、半关闭状态
三、网络编程(==重要==) 1、基础 在网络环境中,要确定一台主机,需要知道彼此的ip;在网络环境中,要想确定一个进程,需要知道ip+port
2、字节序 TCP/IP协议规定,网络数据流应采用大端字节序
大端:低地址存高位,高地址存低位。小端:低地址存低位,高地址存高位。网络字节序 ,就是在网络中进行传输的字节序列,采用的是大端法 。主机字节序 ,就是本地计算机中存储数据采用的字节序列,采用的是小端法
字节序转换的函数
1 2 3 4 5 6 7 8 9 10 11 12 #include <arpa/inet.h> uint32_t htonl (uint32_t hostlong) ;uint16_t htons (uint16_t hostshort) ;uint32_t ntohl (uint32_t netlong) ;uint16_t ntohs (uint16_t netshort) ;in_addr_t inet_addr (const char *cp) ;#include <sys/socket.h> int getsockname (int sockfd, struct sockaddr *addr, socklen_t *addrlen) ;int getpeername (int sockfd, struct sockaddr *addr, socklen_t *addrlen) ;
3、网络通信的原理图(逻辑图)
4、网络通信常规函数(==重要==) 4.1、socket函数 1 2 3 4 5 6 7 8 9 10 11 #include <sys/types.h> #include <sys/socket.h> int socket (int domain, int type, int protocol) ;
==文件描述符,可以将其理解为指针、门把手。==
4.2、bind函数 绑定ip与端口号port
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <sys/types.h> #include <sys/socket.h> int bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen) ;struct sockaddr { sa_family_t sa_family; char sa_data[14 ]; }; struct sockaddr_in { sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; }; struct in_addr { uint32_t s_addr; };
4.3、listen函数 服务器需要监听客户端的连接。
1 2 3 4 5 6 7 8 #include <sys/types.h> #include <sys/socket.h> int listen (int sockfd, int backlog) ;
4.4、accept函数 接收连接请求的函数,==阻塞等待客户端发起连接==
1 2 3 4 5 6 7 8 9 #include <sys/types.h> #include <sys/socket.h> int accept (int sockfd, struct sockaddr *addr, socklen_t *addrlen) ;
4.5、close函数 关闭文件描述符
1 2 3 4 #include <unistd.h> int close (int fd) ;
4.6、connect函数 客户端与服务器进行连接的函数。
1 2 3 4 5 6 7 8 9 #include <sys/types.h> #include <sys/socket.h> int connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen) ;
4.7、读数据read/recv 1 2 3 4 5 6 7 8 9 10 11 12 #include <unistd.h> ssize_t read (int fd, void *buf, size_t count) ;#include <sys/types.h> #include <sys/socket.h> ssize_t recv (int sockfd, void *buf, size_t len, int flags) ;
==注意:read读数据的时候,会将数据直接移走(将内核中的数据移走),会将内核缓冲区清空。==
4.8、写数据write/send 1 2 3 4 5 6 7 8 9 10 #include <unistd.h> ssize_t write (int fd, const void *buf, size_t count) ;#include <sys/types.h> #include <sys/socket.h> ssize_t send (int sockfd, const void *buf, size_t len, int flags) ;
5、代码实现 一、问题回顾 1、什么是协议?TCP/IP协议包括哪几层?什么是TCP协议?什么是三次握手?什么是四次挥手?
2、状态迁移图有哪11中状态?FIN_WAIT_2、TIME_WAIT、CLOSE_WAIT状态?
3、什么是大端存储?什么是小端存储?网络字节序与网络字节序采用什么存储方法?
4、网络编程常规函数有哪些?
二、端口复用 1 2 3 4 5 6 7 8 9 10 11 #include <sys/types.h> #include <sys/socket.h> int getsockopt (int sockfd, int level, int optname,void *optval, socklen_t *optlen) ;int setsockopt (int sockfd, int level, int optname, const void *optval, socklen_t optlen) ;int opt = 1 ;setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt));int opt = 1 ;setsockopt (listenfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof (opt));
三、IO多路复用(==重难点==) 0、原理图
1、select的使用 1.1、函数接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <sys/select.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h> int select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) ;struct timeval { long tv_sec; long tv_usec; }; struct timespec { long tv_sec; long tv_nsec; }; void FD_CLR (int fd, fd_set *set) ;int FD_ISSET (int fd, fd_set *set) ;void FD_SET (int fd, fd_set *set) ;void FD_ZERO (fd_set *set) ;
fd=4 0 1 2 3
fd = 4; 0 1 2 3
1.2、位图
3 5 8
readfs 3、5、8号文件描述符的读事件0 1 1
writefds 3、5号文件描述符的写事件0 1
exceptfds 3、5号文件描述符的异常事件1 0
1.3、优缺点
监听的文件描述符是有上限的1024。
当监听的文件描述符个数比较稀疏的时候(比如6, 600, 1023),循环判断比较麻烦,所以需要自定义数据结构:数组(在我们的代码中就是client数组)
监听集合(也就是位图)与满足监听条件的集合(也就是位图)是同一个,需要将原有集合保存(allset)
如果监听的文件描述符比较密集,那么select效率还是比较不错的。
2、poll的使用 2.1、函数接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <poll.h> int poll (struct pollfd *fds, nfds_t nfds, int timeout) ; struct pollfd { int fd; short events; short revents; }; events/revents:可以被设置为POLLIN (读)/POLLOUT (写)/POLLERR (异常)
2.2、优缺点
突破了文件描述符1024的上限
监听集合与返回的集合分离
监听1000个文件描述符,但是只有3个满足条件,这样也需要全部遍历,效率依旧低
3、epoll的使用 3.1、函数接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <sys/epoll.h> int epoll_create (int size) ;int epoll_create1 (int flags) ;#include <sys/epoll.h> int epoll_ctl (int epfd, int op, int fd, struct epoll_event *event) ;typedef union epoll_data { void *ptr; int fd; uint32_t u32; uint64_t u64; } epoll_data_t ; struct epoll_event { uint32_t events; epoll_data_t data; }; #include <sys/epoll.h> int epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout) ;
3.2、优缺点
文件描述符数目没有上限:通过epoll_ctl()来注册一个文件描述符,内核中使用红黑树 的数据结构来管理所有需要监控的文件描述符。
基于事件就绪通知方式:一旦被监听的某个文件描述符就绪,内核 会采用类似于callback的回调机制 ,迅速激活这个文件描述符,这样随着文件描述符数量的增加,也不会影响判定就绪的性能。
维护就绪队列:当文件描述符就绪,就会被放到内核中的一个就绪队列 中,这样调用epoll_weit获取就绪文件描述符的时候,只要取队列中的元素即可,操作的时间复杂度恒为O(1)
对于大量连续文件描述符活跃的时候,epoll的效果不一定就比select强
3.3、两种模式(==了解==) 水平触发与边沿触发。
四、5种网络IO模型(==重要==) 1、阻塞式IO
2、非阻塞式IO
3、IO多路复用
4、信号驱动IO
==总结:以上四种同步IO而言,第一阶段“等待数据”阶段有区别,但是在第二阶段,都是阻塞的。==
5、异步IO
在五种网络IO模型中,同步机制的时候,第二阶段都是阻塞的,但是对于异步IO而言,第二步是非阻塞的。只有异步IO才能达到真正的非阻塞的。