使用mingw64(gcc版本11.3.0)编译一个64位软件,如下设置socket为非阻塞模式会失败:

1
2
3
4
5
u_long nb = 1;
ret = ioctlsocket(fd, FIONBIO, &nb);
if (ret) {
    error = WSAGetLastError();
}

ret等于SOCKET_ERROR,error等于WSAEOPNOTSUPP(10045),chatgpt给不出有效信息。找到0x8004667E is what you get,试试真好了,看着是mingw中宏定义FIONBIO和原生的不同。

Windows原生winsock2.h定义

1
2
3
4
5
6
7
8
9
10
11
12
#define IOCPARM_MASK    0x7f            /* parameters must be < 128 bytes */
#define IOC_VOID        0x20000000      /* no parameters */
#define IOC_OUT         0x40000000      /* copy out parameters */
#define IOC_IN          0x80000000      /* copy in parameters */
#define IOC_INOUT       (IOC_IN|IOC_OUT)
                                        /* 0x20000000 distinguishes new &
                                           old ioctl's */
#define _IO(x,y)        (IOC_VOID|((x)<<8)|(y))
#define _IOR(x,y,t)     (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
#define _IOW(x,y,t)     (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))

#define FIONBIO         _IOW('f', 126, u_long) /* set/clear non-blocking i/o */

mingw中winsock2.h定义

1
2
3
4
5
6
7
8
9
10
11
#define IOCPARM_MASK 0x7f
#define IOC_VOID 0x20000000
#define IOC_OUT 0x40000000
#define IOC_IN 0x80000000
#define IOC_INOUT (IOC_IN|IOC_OUT)

#define _IO(x,y) (IOC_VOID|((x)<<8)|(y))
#define _IOR(x,y,t) (IOC_OUT|(((__LONG32)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
#define _IOW(x,y,t) (IOC_IN|(((__LONG32)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))

#define FIONBIO _IOW('f',126,u_long)

两者看上去存在__LONG32long的不同,实测发现mingw64环境下FIONBIO等于0x8008667E,而不是期望的0x8004667E,这是由于mingw64中u_long是8个字节导致。