现在的位置: 首页 > 综合 > 正文

poll

2013年12月15日 ⁄ 综合 ⁄ 共 4933字 ⁄ 字号 评论关闭

signal (SIGPIPE ,SIG_IGN) ;  

Linux网络编程 第12讲 tcp 11中状态

 

  1. SIGPIPE产生的原因:        

        如果客户端关闭套接字close 而服务器调用一次RST segment (TCP传输层) 如果服务器再次调用了write ,这个时候就会产生SIGPIPE信号

2 、TIMEOUT会对大并发服务器产生很大的影响

 由于服务器主动关闭连接,服务器就会进入TIME_WAIT ,所以我们要使client先关闭,服务器被动关闭

 3、如果客户端不活跃了,一些客户端不断开连接,这样子就会占用服务器的连接资源,服务器端也有要个机制来踢掉不活跃的连接

 

所以我们使用了nonblocking sokcet + I/O 复用

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <poll.h>
 
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
 
#include <vector>
#include <iostream>
 
#define ERR_EXIT(m) \
        do
\
        { \
                perror(m); \
                exit(EXIT_FAILURE); \
        }
while(0)
 
typedef
std::vector<struct
pollfd> PollFdList;
 
int
main(
void)
{
    // 防止进程由于客户端的关闭产生SIG_PIPE信号而是服务器进程退出
    signal(SIGPIPE, SIG_IGN);
    //SIGCHLD 子进程状态改变后会产生此信号,父进程需要调用一个wait函数以确定发生了什么。
    //如果进程特定设置该信号的配置为SIG_IGN,则调用进程的子进程不产生僵死进程。
    //其实要想防止进程僵死,我们应该在他的父进程里面调用wait,以获取子进程的状态就不会让子进程变成僵死进程了
    signal(SIGCHLD, SIG_IGN);
 
    //int idlefd = open("/dev/null", O_RDONLY | O_CLOEXEC);
    int
listenfd;
 
    //if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    //SOCK_NONBLOCK:非阻塞 ,2.6.2**才有
    //SOCK_CLOEXEC :当进程调用vfork或者fork产生进程时,继承下来的描述是关闭的状态
    //
    if
((listenfd = socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP)) < 0)
        ERR_EXIT("socket");
 
    struct
sockaddr_in servaddr;
    memset(&servaddr, 0,
sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(5188);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
 
    int
on = 1;
    //SOL_SOCKET:在套接字级别上进行设置
    // SO_REUSEADDR,打开或关闭地址复用功能。
    if
(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on,
sizeof(on)) < 0)
        ERR_EXIT("setsockopt");
 
    if
(bind(listenfd, (struct
sockaddr*)&servaddr, sizeof(servaddr)) < 0)
        ERR_EXIT("bind");
    if
(listen(listenfd, SOMAXCONN) < 0)
        ERR_EXIT("listen");
 
    struct
pollfd pfd;
    pfd.fd = listenfd;
    //注册事件
    pfd.events = POLLIN;
 
    PollFdList pollfds;
    pollfds.push_back(pfd);
    //a positive number is returned
    int
nready;
 
    struct
sockaddr_in peeraddr;
    socklen_t peerlen;
    int
connfd;
 
    while
(1)
    {
        //可用POLLIN事件数
        //  -1 :无限等待,直到发送POLLIN事件
        nready = poll(&*pollfds.begin(), pollfds.size(), -1);
        if
(nready == -1)
        {
            if
(errno
== EINTR)
                continue;
 
            ERR_EXIT("poll");
        }
        if
(nready == 0)    // nothing happended
            continue;
 
        //如果POLLIN事件里面包含监听socket,那么监听socket将会
        if
(pollfds[0].revents & POLLIN)
        {
            peerlen =
sizeof(peeraddr);
            //SOCK_NONBLOCK : 非阻塞模式
            connfd = accept4(listenfd, (struct
sockaddr*)&peeraddr,
                        &peerlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
 
            if
(connfd == -1)
                ERR_EXIT("accept4");
 
/*
            if (connfd == -1)
            {
                if (errno == EMFILE)
                {
                    close(idlefd);
                    idlefd = accept(listenfd, NULL, NULL);
                    close(idlefd);
                    idlefd = open("/dev/null", O_RDONLY | O_CLOEXEC);
                    continue;
                }
                else
                    ERR_EXIT("accept4");
            }
*/
 
            pfd.fd = connfd;
            pfd.events = POLLIN;
            pfd.revents = 0;
            pollfds.push_back(pfd);
            --nready;
 
            // 连接成功
            std::cout<<"ip="<<inet_ntoa(peeraddr.sin_addr)<<
                " port="<<ntohs(peeraddr.sin_port)<<std::endl;
            if
(nready == 0)
                continue;
        }
 
        //std::cout<<pollfds.size()<<std::endl;
        //std::cout<<nready<<std::endl;、
        //过滤掉第一个socketfd,也就是监听sdocket
        for
(PollFdList::iterator it=pollfds.begin()+1;
            it != pollfds.end() && nready >0; ++it)
        {
            //如果有POLLIN事件
                if
(it->revents & POLLIN)
                {
                    --nready;
                    connfd = it->fd;
                    char
buf[1024] = {0};
                    int
ret = read(connfd, buf, 1024);
                    if
(ret == -1)
                        ERR_EXIT("read");
                    //如果等于0 ,就是说客户端已关闭,既然是POLLIN事件,那么就表示有数据可读,但现在为0(),也就是所读到了文件的EOF
                    if
(ret == 0)
                    {
                        std::cout<<"client close"<<std::endl;
                        it = pollfds.erase(it);
                        --it;
 
                        close(connfd);
                        continue;
                    }
 
                    std::cout<<buf;
                    write(connfd, buf,
strlen(buf));
 
                }
        }
    }
 
    return
0;
}

抱歉!评论已关闭.