Skip to content

Instantly share code, notes, and snippets.

@PlushBeaver
Last active April 9, 2016 10:22
Show Gist options
  • Save PlushBeaver/b347242586b803f8cf9c2146921825b9 to your computer and use it in GitHub Desktop.
Save PlushBeaver/b347242586b803f8cf9c2146921825b9 to your computer and use it in GitHub Desktop.
Код с практического занятия 08.04.2016
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