1 设置网络socket非阻塞:
u_long has = 1;
ioctl(m_sock, FIONBIO , &has);
这个函数很有可能返回success,却并没有设置成功。 windows对此有优化,对于linux版本应采用fcntl设置。
总结如下:
int
make_socket_nonblocking(sockfd fd)
{
#ifdef WIN32
{
u_long nonblocking = 1;
if (ioctlsocket(fd, FIONBIO, &nonblocking) == SOCKET_ERROR) {
cout << "fcntl failed, fd is : " << fd;
return -1;
}
}
#else
{
int flags;
if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) {
cout << "fcntl failed, fd is : " << fd;
return -1;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
cout << "fcntl failed, fd is : " << fd;
return -1;
}
}
#endif
return 0;
}
2 windows环境下查看错误
使用WSAGetLastError函数需要配置
lib,"ws2_32.lib"
3 EPOLLET这个宏是最小int
EPOLLET这个宏的数值为-2147483648, 是能表示的最小int值。
4 make: 警告:检测到时钟错误。您的创建可能是不完整的。
可以通过ls -l查看具体的是哪个文件的时间错了,就可以对症下药了,直接 " touch 对应文件 " 就可以解决这个问题。
或者读者可以用 " touch * " 来更新整个项目文件的时间,这也可以解决问题。
5 select fd_set 对于不同平台实现是不同的
在windows平台实现
typedef struct fd_set {
u_int fd_count; /* how many are SET? */
SOCKET fd_array[FD_SETSIZE]; /* an array of SOCKETs */
} fd_set;
很明了,一个计数的fd_count,另一个就是SOCKET数组。其中,FD_SETSIZE是可以设置的。整个fd_set的过程实际上就是将对应的 fd_count作为数组下标,数组元素存储的是对应socket fd。比如说当前读事件集合readset的fd_count 为7,当要监控socket fd为5 的读事件到来时,那么readset这个集合中下标为8的数组元素为5,fd_count = 8以此类推。当调用select时,会返回对应读,写集合所有的描述符数组,并且重置内部的fd_count数量,然后分别调用读写函数即可。
下面是fd_set在linux下的实现:
typedef struct
{
/* XPG4.2 requires this member name. Otherwise avoid the name
from the global namespace. */
#ifdef __USE_XOPEN
__fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->fds_bits)
#else
__fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->__fds_bits)
#endif
} fd_set;
根据UNIX网络编程对fd_set的介绍,fd_set是个整数数组,用每个bit位来表示fd的。比如,一个32位整数,则数组第一个整数表示0-31的fd,以此类推,第二个整数表示32-63 查看linux的FD_SET、FD_CLR是用汇编实现的。根据说明可以知道,就是给bit置位。 fd_set在不同平台实现的机制不一样,select第一个参数在linux环境下表示最大描述符数+1。windows无意义。
下面是我根据libevent早期版本实现的一套select模型:
#include "modelmanager.h"
#ifdef WIN32
#include "netmodeldef.h"
#define XFREE(ptr) do { if (ptr) free(ptr); } while (0)
struct win_fd_set {
u_int fd_count;
SOCKET fd_array[1];
};
struct win32op {
unsigned num_fds_in_fd_sets;
int resize_out_sets;
struct win_fd_set *readset_in;
struct win_fd_set *writeset_in;
struct win_fd_set *readset_out;
struct win_fd_set *writeset_out;
struct win_fd_set *exset_out;
unsigned signals_are_broken : 1;
};
static void *win32_init(void *);
static int win32_add(void *, sockfd, short old, short events, void *_idx);
static int win32_del(void *, sockfd, short old, short events, void *_idx);
static int win32_dispatch(void *base, struct timeval *);
static void win32_dealloc(void *);
struct ModelOp win32ops = {
"win32",
win32_init,
win32_add,
win32_del,
win32_dispatch,
win32_dealloc,
};
#define FD_SET_ALLOC_SIZE(n) ((sizeof(struct win_fd_set) + ((n)-1)*sizeof(SOCKET)))
static int
grow_fd_sets(struct win32op *op, unsigned new_num_fds)
{
size_t size;
if( !(new_num_fds >= op->readset_in->fd_count &&
new_num_fds >= op->writeset_in->fd_count) )
return -1;
if( !(new_num_fds >= 1) )
return -1;
size = FD_SET_ALLOC_SIZE(new_num_fds);
if (!(op->readset_in = (struct win_fd_set *)realloc(op->readset_in, size)))
return (-1);
if (!(op->writeset_in = (struct win_fd_set *)realloc(op->writeset_in, size)))
return (-1);
op->resize_out_sets = 1;
op->num_fds_in_fd_sets = new_num_fds;
return (0);
}
static int
do_fd_set(struct win32op *op, struct SocketIndex *ent, SOCKET s, int read)
{
struct win_fd_set *set = read ? op->readset_in : op->writeset_in;
if (read) {
if (ent->read_pos_plus1 > 0)
return (0);
} else {
if (ent->write_pos_plus1 > 0)
return (0);
}
if (set->fd_count == op->num_fds_in_fd_sets) {
if (grow_fd_sets(op, op->num_fds_in_fd_sets*2))
return (-1);
// set pointer will have changed and needs reiniting!
set = read ? op->readset_in : op->writeset_in;
}
set->fd_array[set->fd_count] = s;
if (read)
ent->read_pos_plus1 = set->fd_count+1;
else
ent->write_pos_plus1 = set->fd_count+1;
return (set->fd_count++);
}
static int
do_fd_clear(void *base,
struct win32op *op, struct SocketIndex *ent, int read)
{
ModelManager* pDispatcher = (ModelManager*)base;
int i;
struct win_fd_set *set = read ? op->readset_in : op->writeset_in;
if (read) {
i = ent->read_pos_plus1 - 1;
ent->read_pos_plus1 = 0;
} else {
i = ent->write_pos_plus1 - 1;
ent->write_pos_plus1 = 0;
}
if (i < 0)
return (0);
if (--set->fd_count != (unsigned)i) {
struct SocketIndex *ent2;
SOCKET s2;
s2 = set->fd_array[i] = set->fd_array[set->fd_count];
ent2 = pDispatcher->getSocketIndex( s2 );
if (!ent2) // This indicates a bug.
return (0);
if (read)
ent2->read_pos_plus1 = i+1;
else
ent2->write_pos_plus1 = i+1;
}
return (0);
}
#define NEVENT 32
void *
win32_init(void *base)
{
struct win32op *winop;
size_t size;
if (!(winop = (struct win32op*)malloc( sizeof(struct win32op))))
return NULL;
winop->num_fds_in_fd_sets = NEVENT;
size = FD_SET_ALLOC_SIZE(NEVENT);
if (!(winop->readset_in = (struct win_fd_set *)malloc(size)))
goto err;
if (!(winop->writeset_in = (struct win_fd_set *)malloc(size)))
goto err;
if (!(winop->readset_out = (struct win_fd_set *)malloc(size)))
goto err;
if (!(winop->writeset_out = (struct win_fd_set *)malloc(size)))
goto err;
if (!(winop->exset_out = (struct win_fd_set *)malloc(size)))
goto err;
winop->readset_in->fd_count = winop->writeset_in->fd_count = 0;
winop->readset_out->fd_count = winop->writeset_out->fd_count
= winop->exset_out->fd_count = 0;
winop->resize_out_sets = 0;
return (winop);
err:
XFREE(winop->readset_in);
XFREE(winop->writeset_in);
XFREE(winop->readset_out);
XFREE(winop->writeset_out);
XFREE(winop->exset_out);
XFREE(winop);
return (NULL);
}
int
win32_add(void *base, SOCKET fd,
short old, short events, void *_idx)
{
ModelManager* pDispatcher = (ModelManager*)base;
struct win32op *winop = (struct win32op *)pDispatcher->getModelData();
struct SocketIndex *idx = (struct SocketIndex *)_idx;
if (!(events & (EV_READ|EV_WRITE)))
return (0);
//event_debug(("%s: adding event for %d", __func__, (int)fd));
if (events & EV_READ) {
if (do_fd_set(winop, idx, fd, 1)<0)
return (-1);
}
if (events & EV_WRITE) {
if (do_fd_set(winop, idx, fd, 0)<0)
return (-1);
}
return (0);
}
int
win32_del(void *base, SOCKET fd, short old, short events,
void *_idx)
{
ModelManager* pDispatcher = (ModelManager*)base;
struct win32op *winop = (struct win32op *)pDispatcher->getModelData();
struct SocketIndex *idx = (struct SocketIndex *)_idx;
//event_debug(("%s: Removing event for "EV_SOCK_FMT,__func__, EV_SOCK_ARG(fd)));
if ( (old & EV_READ) && !(events & EV_READ) )
do_fd_clear(base, winop, idx, 1);
if ( (old & EV_WRITE) && !(events & EV_WRITE) )
do_fd_clear(base, winop, idx, 0);
return 0;
}
static void
fd_set_copy(struct win_fd_set *out, const struct win_fd_set *in)
{
out->fd_count = in->fd_count;
memcpy(out->fd_array, in->fd_array, in->fd_count * (sizeof(SOCKET)));
}
/*
static void dump_fd_set(struct win_fd_set *s)
{
unsigned int i;
printf("[ ");
for(i=0;i<s->fd_count;++i)
printf("%d ",(int)s->fd_array[i]);
printf("]\n");
}
*/
int
win32_dispatch(void *base, struct timeval *tv)
{
ModelManager* pDispatcher = (ModelManager*)base;
struct win32op *winop = (struct win32op *)pDispatcher->getModelData();
int res = 0;
unsigned j, i;
int fd_count;
SOCKET s;
if (winop->resize_out_sets) {
size_t size = FD_SET_ALLOC_SIZE(winop->num_fds_in_fd_sets);
if (!(winop->readset_out = (struct win_fd_set *)realloc(winop->readset_out, size)))
return (-1);
if (!(winop->exset_out = (struct win_fd_set *)realloc(winop->exset_out, size)))
return (-1);
if (!(winop->writeset_out = (struct win_fd_set *)realloc(winop->writeset_out, size)))
return (-1);
winop->resize_out_sets = 0;
}
fd_set_copy(winop->readset_out, winop->readset_in);
fd_set_copy(winop->exset_out, winop->writeset_in);
fd_set_copy(winop->writeset_out, winop->writeset_in);
fd_count =
(winop->readset_out->fd_count > winop->writeset_out->fd_count) ?
winop->readset_out->fd_count : winop->writeset_out->fd_count;
if (!fd_count) {
Sleep(tv->tv_usec/1000);
return (0);
}
res = select(fd_count,
(struct fd_set*)winop->readset_out,
(struct fd_set*)winop->writeset_out,
(struct fd_set*)winop->exset_out, tv);
//event_debug(("%s: select returned %d", __func__, res));
if (res <= 0) {
if( res == -1 )
{
printf("error:%d\n", getErrno() );
}
return res;
}
if (winop->readset_out->fd_count) {
i = rand() % winop->readset_out->fd_count;
for (j=0; j<winop->readset_out->fd_count; ++j) {
if (++i >= winop->readset_out->fd_count)
i = 0;
s = winop->readset_out->fd_array[i];
pDispatcher->insertActiveList( s, EV_READ);
}
}
if (winop->exset_out->fd_count) {
i = rand() % winop->exset_out->fd_count;
for (j=0; j<winop->exset_out->fd_count; ++j) {
if (++i >= winop->exset_out->fd_count)
i = 0;
s = winop->exset_out->fd_array[i];
pDispatcher->insertActiveList( s, EV_WRITE);
}
}
if (winop->writeset_out->fd_count) {
SOCKET s;
i = rand() % winop->writeset_out->fd_count;
for (j=0; j<winop->writeset_out->fd_count; ++j) {
if (++i >= winop->writeset_out->fd_count)
i = 0;
s = winop->writeset_out->fd_array[i];
pDispatcher->insertActiveList( s, EV_WRITE);
}
}
return (0);
}
void
win32_dealloc(void *base)
{
ModelManager* pDispatcher = (ModelManager*)base;
struct win32op *winop = (struct win32op *)pDispatcher->getModelData();
if (winop->readset_in)
free(winop->readset_in);
if (winop->writeset_in)
free(winop->writeset_in);
if (winop->readset_out)
free(winop->readset_out);
if (winop->writeset_out)
free(winop->writeset_out);
if (winop->exset_out)
free(winop->exset_out);
memset(winop, 0, sizeof(winop));
free(winop);
}
#endif