这个程序是代理服务器。 我用了poll()。当收到代理请求时,我会创建两个非阻塞套接字并连接并检查超时。
从poll()返回-1,在step3之后。 (连接,错误== EINPROGRESS) 这一次,我用gdb检查了m_fds,这很正常。
这怎么可能?
如果可能,我可以忽略这个结果吗?
这是流程的摘要代码。
int result = -1;
int timeout_ms = 500;
std::vector<struct pollfd> m_fds;
m_fds.reserve(1024);
std::map<int, Session> m_sessions;
std::set<Session> closeSessions;
while (!isStop) {
result = poll(&m_fds[0], m_fds.size(), timeout_ms);
// check connection timeout
for(Session s : m_sessions) {
if (s->isTimeout()) {
closeSessions.insert(s);
}
}
for (Sessions s: closeSession) {
m_sessions.erase(s->getSocket());
struct pollfd* pfd = findFdPtr(s->getSocket());
close(s->getSocket());
pfds->fd = -1;
}
closeSessions.clear();
std::vector<pollfd>::iterator it;
for (it = m_fds.begin(); it != m_fds.end();) {
if (it->fd == -1) {
m_fds.erase(it);
}
else {
++it;
}
}
// connect to proxy targets
if (result < 0) {
if (errno == EINTR) {
continue;
}
// This break will stop the my program.
// result < 0, errno == 0. what happen?
printf("[errno:%d][err_msg:%s]\n", errno, strerror(errno));
break;
}
if (result == 0) {
continue;
}
for (size_t i = 0; i < m_fds.size(); i++) {
// process something.
}
}
这是一个代理序列。我跳过写异常。
Step.1)创建非阻塞套接字。
int sock = socket(PF_INET, SOCK_STREAM, 0);
int socket_option_value = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &socket_option_value,
sizeof(socket_option_value)) < 0) {
close(sock);
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &socket_option_value,
sizeof(socket_option_value)) < 0) {
close(sock);
return -1;
}
int isNonblocking = 1;
if (ioctl(sock, FIONBIO, &isNonblocking) != 0) {
return -1;
}
Step.2)注册m_fds
struct pollfd serverFd;
serverFd.revents = 0;
serverFd.events = 0;
serverFd.fd = sock;
m_fds->push_back(serverFd);
步骤3)尝试连接
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(connectIp);
server_addr.sin_port = htons(connectPort);
int result = connect(m_socket, (struct sockaddr *) &server_addr,
sizeof(server_addr));
// trying...
if (errno == EINPROGRESS) {
// register POLLOUT in m_fds. (ex: pfd.events |= POLLOUT;)
return 0;
}
if (result < 0) {
// unregister POLLOUT in m_fds. (ex: pfd.events &= ~POLLOUT;)
return -1;
}
// unregister POLLOUT in m_fds.
// register POLLIN in m_fds.
Step.4)检查连接。
int result = -1;
int optval = -1;
socklen_t optlen = sizeof(optval);
do {
if (getsockopt(m_socket, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) {
break;
}
if (optval != 0) {
break;
}
result = 0;
}
while (false);
if (result < 0) {
// remove pollfd in m_fds and close socket.
}
else {
// unregister POLLOUT and register POLLIN
// non-blocking -> blocking
int isNonblocking = 0;
ioctl(m_socket, FIONBIO, &isNonblocking) != 0) {
// handling exception
}
}
更新:
*如何处理连接超时。
对不起,我的总结能力不高。