POCO: problème avec ServerSocket::select()
Salut,
J'expérimente avec construction d'un serveur utilisant la POCO librarie. Je me serve de select() pour s'assurer quelles sockets sont préparés pour lire/écrire. Si un client ferme la connexion, j'espéré que receiveBytes() ou sendBytes() sur de côté de serveur me donneraient le valeur zero. En ce cas, le serveur pourrait fermer la connexion de client. C'est le cas si je teste mon serveur avec telnet par exemple. Mais, si le client envoie les requêtes en vitesse et ferme la connexion immediatement (sans attendre la réponse), le serveur s'arrête de marcher avec le message Connection reset by peer [in file "src/ErrorHandler.cpp", line 60]. Voilà le code source
Code:
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
|
#ifndef SERVER_HPP
#define SERVER_HPP
#include <Poco/Runnable.h>
#include <Poco/Net/ServerSocket.h>
#include <Poco/Net/StreamSocket.h>
#include <Poco/Net/Socket.h>
#include <Poco/Timespan.h>
#include <string>
#include <map>
#include <set>
#include <iostream>
using Poco::Runnable;
using Poco::Timespan;
using Poco::Net::ServerSocket;
using Poco::Net::StreamSocket;
using Poco::Net::Socket;
using std::string;
using std::map;
using std::set;
using std::cout;
using std::endl;
class Server : public Runnable
{
public:
Server() : _serverSocket(7000)
{
}
void run()
{
_serverSocket.setReuseAddress(true);
_serverSocket.listen();
while (true)
{
Socket::SocketList reads, writes, empties;
reads.push_back(_serverSocket);
for (set<StreamSocket>::const_iterator it = _in.begin(); it != _in.end(); ++it)
reads.push_back(*it);
for (set<StreamSocket>::const_iterator it = _out.begin(); it != _out.end(); ++it)
writes.push_back(*it);
_serverSocket.select(reads, writes, empties, Timespan());
for (Socket::SocketList::const_iterator it = reads.begin(); it != reads.end(); ++it)
if (*it == _serverSocket)
{
StreamSocket peer = _serverSocket.acceptConnection();
_in.insert(peer);
cout << "client accepted" << endl;
}
else
{
const short BUF_SIZE = 128;
char buf[BUF_SIZE];
StreamSocket peer = static_cast<StreamSocket>(*it);
int result = peer.receiveBytes(reinterpret_cast<void*>(buf), BUF_SIZE - 2);
if (result == 0)
{
cout << "cannot read, peer closed" << endl;
peer.close();
_in.erase(peer);
_out.erase(peer);
}
else
{
string request(buf);
_requests[peer] = request;
_in.erase(peer);
_out.insert(peer);
cout << "request=" << request << endl;
}
}
for (Socket::SocketList::const_iterator it = writes.begin(); it != writes.end(); ++it)
{
StreamSocket peer = static_cast<StreamSocket>(*it);
string echo = _requests[peer];
int result = peer.sendBytes(reinterpret_cast<const void*>(echo.c_str()), echo.size());
if (result == 0)
{
cout << "cannot write, peer closed" << endl;
peer.close();
_in.erase(peer);
_out.erase(peer);
}
else
{
cout << "sent echo=" << echo << endl;
_in.insert(peer);
_out.erase(peer);
}
}
}
}
private:
ServerSocket _serverSocket;
set<StreamSocket> _in;
set<StreamSocket> _out;
map<StreamSocket, string> _requests;
};
#endif // SERVER_HPP |
Code:
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
|
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <cassert>
#include <Poco/Exception.h>
#include <Poco/Net/StreamSocket.h>
#include <Poco/Net/SocketAddress.h>
#include <Poco/Thread.h>
#include <Poco/Runnable.h>
#include <Poco/Mutex.h>
#include <Poco/Format.h>
#include <Poco/Timespan.h>
using std::cout;
using std::endl;
using std::string;
using std::stringstream;
using Poco::Exception;
using Poco::Net::StreamSocket;
using Poco::Net::SocketAddress;
using Poco::Thread;
using Poco::Runnable;
class Client : public Runnable
{
public:
void run()
{
StreamSocket client(SocketAddress("127.0.0.1:7000"));
int rand_no = rand();
stringstream str_no;
str_no << rand_no;
string request = "command=login&username=pera&password=lozinka&no=" + str_no.str();
int len = client.sendBytes(request.c_str(), request.length());
cout << "Client()::run(): request: " << request << ", len=" << len << ", request.length()=" << request.length() << endl;
assert(len == request.length());
if (len == 0)
cout << "Client()::run(): nothing sent, server closed" << endl;
else
client.close();
cout << "Client()::run(): finishing" << endl;
}
};
int main()
{
while (true)
{
try
{
Client c;
c.run();
Thread t;
t.start(c);
t.join();
cout << "main(): finishing, " << endl;
}
catch (Exception& exc)
{
cout << "main(): exc=" << exc.what() << endl;
break;
}
}
return EXIT_SUCCESS;
} |
J'ai essayé cet exemple sous Linux et FreeBSD avec le même résultat. Comment d'éviter la situation comme ça?