The sock_state_cb is function pointer which defines in ares_options. Its signature is as follows:
void (*sock_state_cb)(void *data, ares_socket_t socket_fd, int readable, int writable)
I have no idea that in what scenario the parameter writable will become non-zero. When using ip to serach the domain name? Or when cache the resolving result in local DNS cache? I wrote some code to test. My code is as follows:
namespace {
double getSeconds(struct timeval* tv) {
if (tv)
return static_cast<double>(tv->tv_sec) +
static_cast<double>(tv->tv_usec) / 1000000.0;
else
return -1.0;
}
const char* getSocketType(int type) {
if (type == SOCK_DGRAM)
return "UDP";
else if (type == SOCK_STREAM)
return "TCP";
else
return "Unknown";
}
const bool kDebug = false;
} // namespace
class Resolver : tmuduo::noncopyable {
public:
using Callback = std::function<void(const tmuduo::net::InetAddress&)>;
enum class Option {
kDNSandHostsFile,
kDNSonly,
};
explicit Resolver(tmuduo::net::EventLoop* loop,
Option opt = Option::kDNSandHostsFile): loop_(loop), ctx_(NULL), timerActive_(false)
{
static char lookups[] = "b";
struct ares_options options;
int optmask = ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB;
options.flags = ARES_FLAG_NOCHECKRESP | ARES_FLAG_STAYOPEN | ARES_FLAG_IGNTC;
options.sock_state_cb = &Resolver::ares_sock_state_callback;
options.sock_state_cb_data = this;
optmask |= ARES_OPT_TIMEOUT;
options.timeout = 2;
if (opt == Option::kDNSonly) {
optmask |= ARES_OPT_LOOKUPS;
options.lookups = lookups;
}
int status = ares_init_options(&ctx_, &options, optmask);
if (status != ARES_SUCCESS) {
assert(0);
}
ares_set_socket_callback(ctx_, &Resolver::ares_sock_create_callback, this);
}
~Resolver(){ ares_destroy(ctx_); }
bool resolve(tmuduo::StringArg hostname, const Callback& cb);
private:
struct QueryData {
Resolver* owner;
Callback callback;
QueryData(Resolver* o, const Callback& cb) : owner(o), callback(cb) {}
};
tmuduo::net::EventLoop* loop_;
ares_channel ctx_;
bool timerActive_;
using ChannelList = std::map<int, std::unique_ptr<tmuduo::net::Channel>>;
ChannelList channels_;
/* omitted some other code*/
void onSockStateChange(int sockfd, bool read, bool write) {
auto it = channels_.find(sockfd);
assert(it != channels_.end());
if (read) {
printf("read function has been call\n");
} else if(write){
printf("wirte function has been call\n");
}else {
it->second->disableAll();
it->second->remove();
channels_.erase(it);
}
}
/* omitted some other code */
static void ares_host_callback(void* data, int status, int timeous,
struct hostent* hostent){
QueryData* query = static_cast<QueryData*>(data);
query->owner->onQueryResult(status, hostent, query->callback);
delete query;
}
static int ares_sock_create_callback(int sockfd, int type, void* data){
printf("sockfd= %d, type=%s\n",sockfd,getSocketType(type);
static_cast<Resolver*>(data)->onSockCreate(sockfd, type);
return 0;
}
static void ares_sock_state_callback(void* data, int sockfd, int read,int write){
printf("sockfd = %d, read = %d, write = %d",sockfd, read, write)
static_cast<Resolver*>(data)->onSockStateChange(sockfd, read, write);
}
};
The main file:
void resolveCallback(const string& host, const InetAddress& addr) {
printf("resolveCallback %s -> %s\n", host.c_str(), addr.toIpPort().c_str());
}
void resolve(Resolver* res, const string& host) {
res->resolve(host, std::bind(&resolveCallback, host, _1));
}
int main(int argc, char* argv[]){
...
Resolver resolver(&loop, argc == 1 ? Resolver::Option::kDNSonly
: Resolver::Option::kDNSandHostsFile);
resolve(&resolver, "www.hacker-cube.com");
resolve(&resolver, "www.baidu.com");
resolve(&resolver, "www.jianshu.com");
...
}
For saving the space, I omitted some Irrelevant code. The code shown above can work perfectly. Its output is :
read function has been call
resolveCallback www.baidu.com -> 14.215.177.39:0
resolveCallback www.jianshu.com -> 47.92.108.93:0
resolveCallback www.hacker-cube.com -> 172.67.137.218:0
So my question is what scenario can lead my program to execute the statement printf("wirte function has been call\n");
in function onSockStateChange
?
Aucun commentaire:
Enregistrer un commentaire