int validateSocket(int port) { int socketFD = createAndBind (port); if (socketFD == -1) { abort (); } return socketFD; }
int test1() { int sfd = createAndBind( "12345" ); if( sfd == -1 ) { return -1; } FreeHelper fh_sfd( [&](){ close( sfd ); } ); // 确保回收 sfd int rtv = listen( sfd, SOMAXCONN ); // 系统设置的 /proc/sys/net/core/somaxconn 也是一层限制, 有文章建议设为 1024 if( rtv == -1 ) // http://www.hackbase.com/tech/2008-06-18/41054.html { std::cout << "listen error.\n"; return -1; } int efd = epoll_create( _maxEvents ); if( efd == -1 ) { std::cout << "epoll_create1 error.\n"; return -1; } FreeHelper fh_efd( [&](){ close( efd ); } ); // 确保回收 efd epoll_event e; e.data.fd = sfd; e.events = EPOLLIN | EPOLLET; rtv = epoll_ctl( efd, EPOLL_CTL_ADD, sfd, &e ); if( rtv == -1 ) { std::cout << "epoll_ctl error.\n"; return -1; } auto es = (epoll_event*)calloc( _maxEvents, sizeof(e) ); FreeHelper fh_es( [&](){ free( es ); } ); Dict<int, Binary*> tokens; FreeHelper fh_tokens( [&]() { for( int i = 0; i < tokens._nodes._len; ++i ) { close( tokens._nodes[ i ]->_key ); delete tokens._nodes[ i ]->_value; } } ); while( true ) { int n = epoll_wait( efd, es, _maxEvents, 0 ); // -1 if( n == -1 ) { std::cout << "epoll_wait error.\n"; // if( errno == EINTR ) // 当前不确定这个错误要不要无视 return -1; } for( int i = 0; i < n; ++i ) { auto &ce = es[ i ]; if( ( ce.events & EPOLLERR ) || ( ce.events & EPOLLHUP ) || !( ce.events & EPOLLIN ) ) { std::cout << "epoll error.\n"; continue; } else if( sfd == ce.data.fd ) { while( true ) { sockaddr sa; auto salen = (socklen_t)sizeof(sa); int ifd = accept( sfd, &sa, &salen ); if( ifd == -1 ) { if( ( errno == EAGAIN ) || ( errno == EWOULDBLOCK ) ) { break; // 执行到这里的时候已经处理完所有连接请求,跳出 } else { std::cout << "accept error.\n"; } break; } char hbuf[ NI_MAXHOST ], sbuf[ NI_MAXSERV ]; // 这段代码是取创建的连接的客户端地址信息 rtv = getnameinfo( &sa, salen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV ); if( rtv == 0 ) { std::cout << "accepted. in_fd = " << ifd << ", host = " << hbuf << ", port = " << sbuf << "\n"; } rtv = makeNonBlocking( ifd ); if( rtv == -1 ) { close( ifd ); return -1; } e.data.fd = ifd; e.events = EPOLLIN | EPOLLET; rtv = epoll_ctl( efd, EPOLL_CTL_ADD, ifd, &e ); if( rtv == -1 ) { std::cout << "epoll_ctl error.\n"; close( ifd ); return -1; } std::cout << "tokens.add( ifd : " << ifd << " ).\n"; tokens.add( ifd, new Binary() ); } continue; } else { auto ifd = ce.data.fd; Binary* bin; if( !tokens.tryGet( ifd, bin ) ) { std::cout << "cannot get ifd: " << ifd << " from tokens.\n"; continue; } bool done = false; // 有数据未读,必须读光( edge triggered mode ) do { bin->ensure( 4096 ); rtv = recv( ifd, bin->_buf + bin->_len, 4096, 0 ); if( rtv == -1 ) { if( errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK ) { break; } std::cout << "read error.\n"; done = true; break; } else if( rtv == 0 ) // 0 长度表示连接已断开 { done = true; break; } bin->_len += rtv; } while( rtv == 4096 ); // 按某文章的说法,读到的字节数小于 buf 长,就表明已经读完了 if( !done ) // 顺利读完数据到此 { LabBegin: // 这里使用 readIdx 来存上一次的扫描点 for( ; bin->_readIdx < bin->_len; ++bin->_readIdx ) { if( bin->_buf[ bin->_readIdx ] == '\n' ) { ++bin->_readIdx; // 跳过空格 if( bin->_buf[ 0 ] == '`' ) // 退出 { return 0; } else if( bin->_buf[ 0 ] == ' ' ) // 广播 { for( int i = 0; i < tokens._nodes._len; ++i ) { auto cifd = tokens._nodes[ i ]->_key; if( cifd == ifd ) continue; rtv = write( cifd, bin->_buf, bin->_readIdx ); if( rtv == -1 ) { close( cifd ); Binary* bin; if( !tokens.tryRemove( cifd, bin ) ) { std::cout << "cannot remove cifd: " << cifd << " from tokens.\n"; } else { delete bin; } } } } rtv = send( ifd, bin->_buf, bin->_readIdx, 0 ); // 回发收到的数据 \n 截止 if( rtv == -1 ) { std::cout << "write error.\n"; done = true; break; } memmove( bin->_buf, bin->_buf + bin->_readIdx, bin->_len - bin->_readIdx ); bin->_len = bin->_len - bin->_readIdx; bin->_readIdx = 0; if( bin->_len ) goto LabBegin; break; } } } if( done ) // 出问题需要关闭 ifd { std::cout << "closed. ce.data.fd = " << ifd << "\n"; close( ifd ); Binary* bin; if( !tokens.tryRemove( ifd, bin ) ) { std::cout << "cannot remove ifd: " << ifd << " from tokens.\n"; } else { delete bin; } } } } // todo: logic code here usleep( 1 ); } return 0; }