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

Posted 恋恋风辰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络编程一些常见问题总结相关的知识,希望对你有一定的参考价值。

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 * " 来更新整个项目文件的时间,这也可以解决问题。

 

5select 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模型:

 

 

 

  1 #include "modelmanager.h"
  2 
  3 
  4 #ifdef WIN32
  5 #include "netmodeldef.h"
  6 #define XFREE(ptr) do { if (ptr) free(ptr); } while (0)
  7 
  8 
  9 struct win_fd_set {
 10     u_int fd_count;
 11     SOCKET fd_array[1];
 12 };
 13 
 14 struct win32op {
 15     unsigned num_fds_in_fd_sets;
 16     int resize_out_sets;
 17     struct win_fd_set *readset_in;
 18     struct win_fd_set *writeset_in;
 19     struct win_fd_set *readset_out;
 20     struct win_fd_set *writeset_out;
 21     struct win_fd_set *exset_out;
 22     unsigned signals_are_broken : 1;
 23 };
 24 
 25 static void *win32_init(void *);
 26 static int win32_add(void *, sockfd, short old, short events, void *_idx);
 27 static int win32_del(void *, sockfd, short old, short events, void *_idx);
 28 static int win32_dispatch(void *base, struct timeval *);
 29 static void win32_dealloc(void *);
 30 
 31 struct ModelOp win32ops = {
 32     "win32",
 33     win32_init,
 34     win32_add,
 35     win32_del,
 36     win32_dispatch,
 37     win32_dealloc,
 38 };
 39 
 40 #define FD_SET_ALLOC_SIZE(n) ((sizeof(struct win_fd_set) + ((n)-1)*sizeof(SOCKET)))
 41 
 42 static int
 43 grow_fd_sets(struct win32op *op, unsigned new_num_fds)
 44 {
 45     size_t size;
 46 
 47     if( !(new_num_fds >= op->readset_in->fd_count &&
 48         new_num_fds >= op->writeset_in->fd_count) )
 49         return -1;
 50     if( !(new_num_fds >= 1) )
 51         return -1;
 52 
 53     size = FD_SET_ALLOC_SIZE(new_num_fds);
 54     if (!(op->readset_in = (struct win_fd_set *)realloc(op->readset_in, size)))
 55         return (-1);
 56     if (!(op->writeset_in = (struct win_fd_set *)realloc(op->writeset_in, size)))
 57         return (-1);
 58     op->resize_out_sets = 1;
 59     op->num_fds_in_fd_sets = new_num_fds;
 60     return (0);
 61 }
 62 
 63 static int
 64 do_fd_set(struct win32op *op, struct SocketIndex *ent, SOCKET s, int read)
 65 {
 66     struct win_fd_set *set = read ? op->readset_in : op->writeset_in;
 67     
 68     if (read) {
 69         if (ent->read_pos_plus1 > 0)
 70             return (0);
 71     } else {
 72         if (ent->write_pos_plus1 > 0)
 73             return (0);
 74     }
 75 
 76     if (set->fd_count == op->num_fds_in_fd_sets) {
 77         if (grow_fd_sets(op, op->num_fds_in_fd_sets*2))
 78             return (-1);
 79         // set pointer will have changed and needs reiniting!
 80         set = read ? op->readset_in : op->writeset_in;
 81     }
 82     set->fd_array[set->fd_count] = s;
 83     if (read)
 84         ent->read_pos_plus1 = set->fd_count+1;
 85     else
 86         ent->write_pos_plus1 = set->fd_count+1;
 87     return (set->fd_count++);
 88 }
 89 
 90 static int
 91 do_fd_clear(void *base,
 92 struct win32op *op, struct SocketIndex *ent, int read)
 93 {
 94     ModelManager* pDispatcher = (ModelManager*)base;
 95 
 96     int i;
 97     struct win_fd_set *set = read ? op->readset_in : op->writeset_in;
 98     if (read) {
 99         i = ent->read_pos_plus1 - 1;
100         ent->read_pos_plus1 = 0;
101     } else {
102         i = ent->write_pos_plus1 - 1;
103         ent->write_pos_plus1 = 0;
104     }
105     if (i < 0)
106         return (0);
107     if (--set->fd_count != (unsigned)i) {
108         struct SocketIndex *ent2;
109         SOCKET s2;
110         s2 = set->fd_array[i] = set->fd_array[set->fd_count];
111 
112         ent2 = pDispatcher->getSocketIndex( s2 );
113 
114         if (!ent2) // This indicates a bug.
115             return (0);
116         if (read)
117             ent2->read_pos_plus1 = i+1;
118         else
119             ent2->write_pos_plus1 = i+1;
120     }
121     return (0);
122 }
123 
124 #define NEVENT 32
125 void *
126 win32_init(void *base)
127 {
128     struct win32op *winop;
129     size_t size;
130     if (!(winop = (struct win32op*)malloc( sizeof(struct win32op))))
131         return NULL;
132     winop->num_fds_in_fd_sets = NEVENT;
133     size = FD_SET_ALLOC_SIZE(NEVENT);
134     if (!(winop->readset_in = (struct win_fd_set *)malloc(size)))
135         goto err;
136     if (!(winop->writeset_in = (struct win_fd_set *)malloc(size)))
137         goto err;
138     if (!(winop->readset_out = (struct win_fd_set *)malloc(size)))
139         goto err;
140     if (!(winop->writeset_out = (struct win_fd_set *)malloc(size)))
141         goto err;
142     if (!(winop->exset_out = (struct win_fd_set *)malloc(size)))
143         goto err;
144     winop->readset_in->fd_count = winop->writeset_in->fd_count = 0;
145     winop->readset_out->fd_count = winop->writeset_out->fd_count
146         = winop->exset_out->fd_count = 0;
147 
148     winop->resize_out_sets = 0;
149 
150     return (winop);
151 err:
152     XFREE(winop->readset_in);
153     XFREE(winop->writeset_in);
154     XFREE(winop->readset_out);
155     XFREE(winop->writeset_out);
156     XFREE(winop->exset_out);
157     XFREE(winop);
158     return (NULL);
159 }
160 
161 int
162 win32_add(void *base, SOCKET fd,
163           short old, short events, void *_idx)
164 {
165     ModelManager* pDispatcher = (ModelManager*)base;
166     struct win32op *winop = (struct win32op *)pDispatcher->getModelData();
167     struct SocketIndex *idx = (struct SocketIndex *)_idx;
168 
169     if (!(events & (EV_READ|EV_WRITE)))
170         return (0);
171 
172     //event_debug(("%s: adding event for %d", __func__, (int)fd));
173     if (events & EV_READ) {
174         if (do_fd_set(winop, idx, fd, 1)<0)
175             return (-1);
176     }
177     if (events & EV_WRITE) {
178         if (do_fd_set(winop, idx, fd, 0)<0)
179             return (-1);
180     }
181     return (0);
182 }
183 
184 int
185 win32_del(void *base, SOCKET fd, short old, short events,
186           void *_idx)
187 {
188     ModelManager* pDispatcher = (ModelManager*)base;
189     struct win32op *winop = (struct win32op *)pDispatcher->getModelData();
190     struct SocketIndex *idx = (struct SocketIndex *)_idx;
191 
192     //event_debug(("%s: Removing event for "EV_SOCK_FMT,__func__, EV_SOCK_ARG(fd)));
193     if ( (old & EV_READ) && !(events & EV_READ) )
194         do_fd_clear(base, winop, idx, 1);
195     if ( (old & EV_WRITE) && !(events & EV_WRITE) )
196         do_fd_clear(base, winop, idx, 0);
197 
198     return 0;
199 }
200 
201 static void
202 fd_set_copy(struct win_fd_set *out, const struct win_fd_set *in)
203 {
204     out->fd_count = in->fd_count;
205     memcpy(out->fd_array, in->fd_array, in->fd_count * (sizeof(SOCKET)));
206 }
207 
208 /*
209 static void dump_fd_set(struct win_fd_set *s)
210 {
211 unsigned int i;
212 printf("[ ");
213 for(i=0;i<s->fd_count;++i)
214 printf("%d ",(int)s->fd_array[i]);
215 printf("]\\n");
216 }
217 */
218 
219 int
220 win32_dispatch(void *base, struct timeval *tv)
221 {
222     ModelManager* pDispatcher = (ModelManager*)base;
223     struct win32op *winop = (struct win32op *)pDispatcher->getModelData();
224     int res = 0;
225     unsigned j, i;
226     int fd_count;
227     SOCKET s;
228 
229     if (winop->resize_out_sets) {
230         size_t size = FD_SET_ALLOC_SIZE(winop->num_fds_in_fd_sets);
231         if (!(winop->readset_out = (struct win_fd_set *)realloc(winop->readset_out, size)))
232             return (-1);
233         if (!(winop->exset_out = (struct win_fd_set *)realloc(winop->exset_out, size)))
234             return (-1);
235         if (!(winop->writeset_out = (struct win_fd_set *)realloc(winop->writeset_out, size)))
236             return (-1);
237         winop->resize_out_sets = 0;
238     }
239 
240     fd_set_copy(winop->readset_out, winop->readset_in);
241     fd_set_copy(winop->exset_out, winop->writeset_in);
242     fd_set_copy(winop->writeset_out, winop->writeset_in);
243 
244     fd_count =
245         (winop->readset_out->fd_count > winop->writeset_out->fd_count) ?
246         winop->readset_out->fd_count : winop->writeset_out->fd_count;
247 
248     if (!fd_count) {
249         Sleep(tv->tv_usec/1000);
250         return (0);
251     }
252 
253 
254     res = select(fd_count,
255         (struct fd_set*)winop->readset_out,
256         (struct fd_set*)winop->writeset_out,
257         (struct fd_set*)winop->exset_out, tv);
258 
259 
260     //event_debug(("%s: select returned %d", __func__, res));
261 
262     if (res <= 0) {
263         if( res == -1 )
264         {
265             printf("error:%d\\n", getErrno() );
266         }
267         return res;
268     }
269 
270     if (winop->readset_out->fd_count) {
271         i = rand() % winop->readset_out->fd_count;
272         for (j=0; j<winop->readset_out->fd_count; ++j) {
273             if (++i >= winop->readset_out->fd_count)
274                 i = 0;
275             s = winop->readset_out->fd_array[i];
276             pDispatcher->insertActiveList( s, EV_READ);
277         }
278     }
279     if (winop->exset_out->fd_count) {
280         i = rand() % winop->exset_out->fd_count;
281         for (j=0; j<winop->exset_out->fd_count; ++j) {
282             if (++i >= winop->exset_out->fd_count)
283                 i = 0;
284             s = winop->exset_out->fd_array[i];
285             pDispatcher->insertActiveList( s, EV_WRITE);
286         }
287     }
288     if (winop->writeset_out->fd_count) {
289         SOCKET s;
290         i = rand() % winop->writeset_out->fd_count;
291         for (j=0; j<winop->writeset_out->fd_count; ++j) {
292             if (++i >= winop->writeset_out->fd_count)
293                 i = 0;
294             s = winop->writeset_out->fd_array[i];
295             pDispatcher->insertActiveList( s, EV_WRITE);
296         }
297     }
298     return (0);
299 }
300 
301 void
302 win32_dealloc(void *base)
303 {
304     ModelManager* pDispatcher = (ModelManager*)base;
305     struct win32op *winop = (struct win32op *)pDispatcher->getModelData();
306 
307     if (winop->readset_in)
308         free(winop->readset_in);
309     if (winop->writeset_in)
310         free(winop->writeset_in);
311     if (winop->readset_out)
312         free(winop->readset_out);
313     if (winop->writeset_out)
314         free(winop->writeset_out);
315     if (winop->exset_out)
316         free(winop->exset_out);
317 
318 
319     memset(winop, 0, sizeof(winop));
320     free(winop);
321 }
322 
323 #endif


到此总结完毕,关注我的公众号

 

 

 

 


 

以上是关于网络编程一些常见问题总结的主要内容,如果未能解决你的问题,请参考以下文章

好的编程习惯

使用 Git 来管理 Xcode 中的代码片段

全栈编程系列SpringBoot整合Shiro(含KickoutSessionControlFilter并发在线人数控制以及不生效问题配置启动异常No SecurityManager...)(代码片段

BootStrap有用代码片段(持续总结)

常用编程思想与算法

是否有在单个活动中处理多个片段的 Android 设计模式?