C++实战——Socket初始化流程

文章代码来源:高并发Web服务器

Socket 初始化流程

  1. 首先检查端口是否合法,不可使用公知端口,以及超出最大端口大小
  2. 创建监听文件描述符,当有连接到来时会产生事件,被Epoll监测到
  3. 文件描述符绑定ip地址
  4. 开始监听,并将监听文件描述符添加进Epoll的事件监听集合中(具体使用那种数据结构没有仔细探究)
  5. 设置监听文件描述符非阻塞。这一步很重要,不然如果一直没有连接到来服务器会被阻塞。

以上这些步骤所需要的功能底层都用c语言实现(就是一些经典的库函数),但是都做了良好的封装

初始化 Socket代码:

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
* Create listenFd */
bool WebServer::InitSocket_() {
int ret;
struct sockaddr_in addr;
//首先检查端口的合法性
if(port_ > 65535 || port_ < 1024) {
LOG_ERROR("Port:%d error!", port_);
return false;
}

addr.sin_family = AF_INET; //IPv4
addr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY 意为可以绑定任意可用的IP地址
addr.sin_port = htons(port_);

//优雅关闭
struct linger optLinger = { 0 };
if(openLinger_) {
/* 优雅关闭: 直到所剩数据发送完毕或超时 */
optLinger.l_onoff = 1;
optLinger.l_linger = 1;
}

//返回监听成员描述符
listenFd_ = socket(AF_INET, SOCK_STREAM, 0);
if(listenFd_ < 0) {
LOG_ERROR("Create socket error!", port_);
return false;
}

//
ret = setsockopt(listenFd_, SOL_SOCKET, SO_LINGER, &optLinger, sizeof(optLinger));
if(ret < 0) {
close(listenFd_);
LOG_ERROR("Init linger error!", port_);
return false;
}

int optval = 1;
/* 端口复用 */
/* 只有最后一个套接字会正常接收数据。 */
ret = setsockopt(listenFd_, SOL_SOCKET, SO_REUSEADDR, (const void*)&optval, sizeof(int));
if(ret == -1) {
LOG_ERROR("set socket setsockopt error !");
close(listenFd_);
return false;
}
//绑定
ret = bind(listenFd_, (struct sockaddr *)&addr, sizeof(addr));
if(ret < 0) {
LOG_ERROR("Bind Port:%d error!", port_);
close(listenFd_);
return false;
}
//监听
ret = listen(listenFd_, 6);
if(ret < 0) {
LOG_ERROR("Listen port:%d error!", port_);
close(listenFd_);
return false;
}
//将监听文件描述符 与 事件 添加进Epoll
ret = epoller_->AddFd(listenFd_, listenEvent_ | EPOLLIN);
if(ret == 0) {
LOG_ERROR("Add listen error!");
close(listenFd_);
return false;
}
//设置监听文件描述符非阻塞
SetFdNonblock(listenFd_);
LOG_INFO("Server port:%d", port_);
return true;
}