Last active
April 9, 2016 10:22
-
-
Save PlushBeaver/b347242586b803f8cf9c2146921825b9 to your computer and use it in GitHub Desktop.
Код с практического занятия 08.04.2016
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct Client { | |
int channel; | |
std::vector<char> buffer; | |
uint64_t to_receive = 8; | |
uint64_t received = 0; | |
bool on_receive(); | |
}; | |
int main() { | |
sockaddr_in address; // Считаем, что как-то эта страктура заполнена. | |
int yes = 1; | |
auto listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | |
bind(listener, (sockaddr*)&address, sizeof address); | |
ioctl(listener, FIONBIO, &yes); | |
listen(listener, SOMAXCONN); | |
fd_set readers, failed, writers; | |
std::vector<Client> clients; | |
// (1) | |
while (true) { | |
int max_fd = -1; | |
FD_ZERO(&readers); | |
FD_SET(listener, &readers); | |
for (Client& client: clients) { | |
FD_SET(client.channel, &readers); | |
} | |
// (2) | |
FD_ZERO(&writers); | |
// N.B. Нужно опустошать множество, если оно должно быть пустым. | |
// В альнейшем здесь оно будет заполняться сокетами клиентов, | |
// которым нужно отправлять ответ. | |
FD_ZERO(&failed); | |
FD_SET(listener, &failed); | |
for (Client& client : clients) { | |
FD_SET(client.channel, &failed); | |
max_fd = max(max_fd, client.channel); | |
} | |
// (3) | |
max_fd = max(max_fd, listener); | |
int result = select(max_fd + 1, &readers, &writers, &failed, nullptr); | |
if (result <= 0) { | |
perror("select"); | |
break; | |
} | |
else { | |
if (FD_ISSET(listener, &failed)) { | |
// Ошибка сокета-слушателя --- нужно обработать её (см. ниже). | |
} | |
else if (FD_ISSET(listener, &readers)) { | |
auto channel = accept(listener, nullptr, nullptr); | |
Client client; | |
client.channel = channel; | |
clients.push_back(client); | |
ioctl(chanel, FIONBIO, &yes); | |
} | |
// (4) | |
for (auto it = clients.begin(); it != clients.end();) { | |
if (FD_ISSET(client.channel, &failed)) { | |
// N.B.: на лекции был дан некорректный код, вот верный. | |
int code; | |
socklen_t code_size = sizeof(code); | |
getsockopt(client.channel, SOL_SOCKET, SO_ERROR, &code, &code_size); | |
close(client.channel); | |
it = clients.remove(it); | |
} | |
else if (FD_ISSET(client.channel, &readers)) { | |
client.on_receive(); | |
} | |
// (5) | |
++it; | |
} | |
} | |
} | |
} | |
bool Client::on_receive() { | |
while (true) { | |
if (received < 8){ | |
int result = recv(channel, (char*)&to_receive, 8 - received, 0); | |
if (result <= 0) { | |
if (errno == EWOULDBLOCK) { | |
return true; | |
} | |
return false; | |
} | |
else { | |
received += result; | |
} | |
} | |
else { | |
buffer.resize(to_receive - 8); | |
// N.B.: восемь первых байт не хранятся в buffer, поэтому их исключаем. | |
int result = recv(channel, &buffer[received - 8], to_receive - received, 0); | |
// Здесь мы остановились. | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment