网络编程一些常见问题总结

1 设置网络socket非阻塞:

1
2
u_long has = 1;
ioctl(m_sock, FIONBIO , &has);

这个函数很有可能返回success,却并没有设置成功。
windows对此有优化,对于linux版本应采用fcntl设置。

总结如下:

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
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环境下查看错误

1
2
3
使用WSAGetLastError函数需要配置

lib,"ws2_32.lib"

3 EPOLLET这个宏是最小int

EPOLLET这个宏的数值为-2147483648, 是能表示的最小int值。

4 make: 警告:检测到时钟错误。您的创建可能是不完整的。

可以通过ls -l查看具体的是哪个文件的时间错了,就可以对症下药了,直接 “ touch 对应文件 “ 就可以解决这个问题。

或者读者可以用 “ touch * “ 来更新整个项目文件的时间,这也可以解决问题。

5 select fd_set 对于不同平台实现是不同的

在windows平台实现

1
2
3
4
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下的实现:

1
2
3
4
5
6
7
8
9
10
11
12
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模型:

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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
#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