理论知识点
TCP协议的三次握手的触发API
- connect : 第一次握手信息
- 第二次,第三次都是被动处理,无需调用接口
- accept不参与三次握手,取出三次握手成功的描述符
socket描述符的合理大小
属于linux 系统描述符fd 的一部分:
f
d
∈
[
0
,
1
,
2
…
…
]
fd\in[0,1,2……]
fd∈[0,1,2……]
总之
f
d
>
=
0
fd>=0
fd>=0
把socket状态从主动发送状态转变为被动监听状态
listen + TCP的描述符
send(sockfd, buf, 5, 0)
表示的是向文件描述符为sockfd 的目的地址发送以buf 为首地址,5个字节的内容
端口号的范围
unsigned short 16bit [0 , 65535]
大端模式,小端模式
条件 大端:0x12345678 低位地址 0x12 小端:0x12345678 低位地址 0x78
int空间的传递
网络序 :大端 CPU序 :大/小端
htonl() –“Host to Network Long” 将一个无符号长整型数值转换为网络字节序ntohl() –“Network to Host Long” 将一个网络字节序转换为无符号长整型数值htons() –“Host to Network Short” 将一个无符号短整型数值转换为网络字节序ntohs() –“Network to Host Short” 将一个网络字节序转换为无符号短整型数值
服务器编程模型中独有的API
socket 、bind 、send 、recv
connect 客户端
listen 、accept 服务器
HTTP状态码:302 404
- 2xx : 成功
- 3xx : 特殊功能 302 重定向
- 4xx : 客户端请求错误,服务器拒绝服务 404 not found
- 5xx : 服务器服务异常
HTTP请求的动作包含哪些
HTTP请求组成
请求报文 = 请求行+请求头+请求数据
HTTP的9个请求动作
HTTP1.0:
GET :请求指定页面的信息,并返回实体主体POST :向指定资源提交数据进行处理请求,数据存在请求体HEAD : 类似get,但不返回具体内容,用于获取报头
HTTP1.1:
PUT :完整替换更新指定资源数据,没有就新增DELETE :删除指定资源的数据PATCH :部分更新指定资源的数据OPTIONS :允许客户端查看服务器的支持的http请求方法CONNECT :预留给能将连接改为管道的代理服务器TRACE :追踪服务器收到的请求,用于测试或诊断
查看端口号命令
netstat
大概这样:
多进程高并发服务器 fork调用的时机
接收到新连接后,单独开辟一个子进程独立处理这个新连接,也就是accept 之后
UDP的通信API
socket
bind
sendto
recvfrom
DNS解析
通过gethostbyname 函数即可解析
函数原型:
struct hostent *gethostbyname(const char *hostname);
通过输入域名我们可以将其解析,然后返回一个hostent 的封装数据,这个数据的结构如下:
struct hostent{
char *h_name;
char **h_aliases;
int h_addrtype;
int h_length;
char **h_addr_list;
}
这样我们就能解析域名并得到真正的IP地址
TCP/IP通信 全双工
全双工通过一个socket文件描述符允许数据从两边同时发送和接收
这边总结一下其他的知识点:
单工
单工指的是数据只能从一方传输,并不能实现双方通信
例如:电视、广播、收音机等
半双工
半双工指的是数据能从两方传输,但是同一时间数据只能在一个方向传输
例如:对讲机
全双工
全双工指的是数据可以从两个方向同时传输
例如:电话
零散知识点
socket 不仅仅支持TCP/IP协议和本地进程间通信- 如果系统TCP使用了80端口,那么UDP也可以使用80端口
- TCP在释放链接过程中会有四次挥手的过程
- HTTP协议是应用层协议,他传输层是基于TCP协议的
- 如果服务器不调用
accept 函数,那么三次握手不会失效 - 如果两台电脑能
ping 通,说明两台电脑的网络层是相通的。 epoll 性能比select 性能各有所长- UDP编程中,需要指定对方的IP和端口号也能通信。
sendto 可以 send 可以(connect后) - CPU有小端模式,也有大端模式,处理数据
Ctrl+C 组合键实际触发的信号是 SIGINT - 在HTTP1.1规范中,
OPTIONS 动作代表允许客户端查看服务器的性能 - 在
sockaddr_in 结构体中,sin_addr 中一般使用INADDR_ANY 宏代表可以接收任意本地设备的网络数据 inet_aton 函数可以将主机字节序结构的IP地址转换为网络字节序- 在select结构中,
FD_ISSET() 宏用来判断文件描述符是否在文件集合中
如何设计高并发服务器
通过epoll 多路复用实现高并发服务器
优点
-
epoll 没有最大并发连接限制,上限是最大可打开文件的数目,一般这个数目和系统内存有关,但是考虑到服务器的内存一般不小,所以可以实现高并发 -
效率有明显提升,epoll 对于句柄事件的选择和select 、poll 的遍历不同,epoll 是事件相应的,即:句柄事件来到后,立即选择出来,复杂度为常数级别
O
(
1
)
O(1)
O(1),不需要遍历,内核将句柄通过红黑树保存,所以随着句柄数目的增多,IO的效率也不会随之线性下降(只是会稍微下降一点) -
内存拷贝, select 让内核把 FD 消息通知给用户空间的时候使用了内存拷贝的方式,开销较大,但是epoll 在这点上使用了共享内存的方式,这个内存拷贝也省略了。
实现机制
epoll 的设计和实现与select完全不同。epoll 通过在Linux内核中申请一个简易的文件系统,把原先的select/poll调用分成了3个部分:
调用epoll_create() 建立一个epoll 对象(在epoll 文件系统中为这个句柄对象分配资源)
调用epoll_ctl 向epoll 对象中添加这上万个连接的套接字
调用epoll_wait 收集发生的事件的连接
只需要在进程启动时建立一个epoll 对象,然后在需要的时候向这个epoll 对象中添加或者删除连接。同时,epoll_wait 的效率也非常高,因为调用epoll_wait 时,并没有直接向操作系统复制这数万个连接的句柄数据,内核也不需要去遍历全部的连接。所以可以应对高并发的情况
用一个图来表明epoll处理的逻辑关系:
代码知识点
初始化监听描述符 怎么做?可以不考虑出错处理
- 创建
socket - 填充自己信息,公布端口
struct sockaddr_in self 、 bind - 改变为监听状态
listen
eg:
int init_listen(){
int listen_fd;
int ret;
struct sockaddr_in server_addr;
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0) {
fprintf(stderr, "fail to socket : %s\n", strerror(errno));
return -1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(listen_fd, (struct sockaddr *) &server_addr, sizeof(server_addr));
if (ret < 0) {
perror("fail to bind");
return -1;
}
listen(listen_fd, 5);
return listen_fd;
}
服务器如何获得三次握手的新描述符?
int listen_handler(int listen_fd) {
int new_fd;
new_fd = accept(listen_fd, NULL, NULL);
if (new_fd < 0) {
perror("fail to accept");
return -1;
}
return new_fd;
}
循环读取文件,发送文件的方法?
void read_func() {
char buf[1024];
fd = open(xxxx);
ret = read(fd, buf, sizeof(buf));
while (ret) {
if (ret < 0) {
xxxx;break;
}
send(xxx, buf, ret);
ret = read(fd, buf, sizeof(buf));
}
}
大小端的检查方法
void judge()
{
int i = 48,*p = &i;
char c = *((char*)p);
puts(c=='0'?"小端":"大端");
}
参考文献
select、poll、epoll - IO模型超详解
IO模型之IO多路复用 异步IO select poll epoll 的用法
Linux下的socket编程实践(九) epoll实现高并发的原理及其使用
|