问题代码如下,当时我是想用libevent在win32上监听一个端口的输入。
/*
* Compile with:
* cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent
* see
* http://d.hatena.ne.jp/mtaneda/20090302/1235998584
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifndef WIN32
#include <sys/queue.h>
#include <unistd.h>
#include <sys/time.h>
#else
#include <winsock.h>
#include <windows.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <event.h>
static void read_handler(int fd, short event, void *arg)
{
char buf[256] = {0};
struct event *ev;
ZeroMemory(buf, sizeof(buf));
ev = (struct event*)arg;
if(event & EV_READ)
{
if(recv(fd, buf, sizeof(buf), 0)<=0)
{
event_del(ev);
free(ev);
closesocket(fd);
}
else
{
printf("[read_handler] read=%s\n", buf);
}
}
}
static void accept_handler(int fd, short event, void *arg)
{
struct sockaddr_in addr;
struct event *new_ev;
int new_fd;
int addrlen;
addrlen = sizeof(addr);
if(event & EV_READ)
{
printf("[accept_handler]\n");
new_fd = accept(fd, (struct sockaddr*)&addr, &addrlen);
new_ev = malloc(sizeof(struct event));
event_set(new_ev, new_fd, EV_READ|EV_PERSIST, read_handler, new_ev);
event_add(new_ev, NULL);
}
}
int main (int argc, char **argv)
{
struct event ev;
SOCKET sock;
int on;
int rc;
struct sockaddr_in addr;
int server_port = 8888;
WORD version = MAKEWORD (1,1);
WSADATA wsadata;
WSAStartup (version, &wsadata);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
perror("socket() failed");
WSACleanup();
exit(-1);
}
rc = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
if (rc < 0)
{
perror("setsockopt() failed");
closesocket(sock);
WSACleanup();
exit(-1);
}
rc = ioctlsocket(sock, FIONBIO, &on);
if (rc < 0)
{
perror("ioctl() failed");
closesocket(sock);
WSACleanup();
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(server_port);
rc = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
if (rc < 0)
{
perror("bind() failed");
closesocket(sock);
WSACleanup();
exit(-1);
}
rc = listen(sock, 32);
if (rc < 0)
{
perror("listen() failed");
closesocket(sock);
WSACleanup();
exit(-1);
}
event_init();
event_set(&ev, (int)socket, EV_READ | EV_PERSIST, accept_handler, &ev);
event_add(&ev, NULL);
event_dispatch();
closesocket(sock);
WSACleanup();
return (0);
}
这个程序并没有在event_dispatch()处进入监听状态,而是在main函数最后的return (0);处退出,
后来发现bug其实在这里
event_init(); event_set(&ev, (int)socket, EV_READ | EV_PERSIST, accept_handler, &ev); event_add(&ev, NULL);
我在重命名socket对象的名称时忘记改这里。
结果代码把socket这个函数显式地转换为int型,
当时以为强制转换是必须,但事实上不是。
libevent在运行时也没有发现这个问题,于是直接退出event_dispatch()循环。
正确的写法是
event_init(); event_set(&ev, sock, EV_READ | EV_PERSIST, accept_handler, &ev); event_add(&ev, NULL);
结论是:
C代码中任何显式和隐式的类型转换都需要加倍小心,尤其是在重构代码更改变量名的时候。
尽量避免类型转换,不要完全依赖某个特定的C编译器的检查(这里我使用的是VC2008)。
2746

被折叠的 条评论
为什么被折叠?



