【发布时间】:2015-10-17 23:37:02
【问题描述】:
我正在使用 MinGW 编译器和 winsock2 API 为 Windows 编写自定义 TCP 服务器。
我有这段代码:
TCPSocket TCPSocket::accept() {
TCPSocket clSocket;
struct sockaddr_in clAddr;
socklen_t clAddrSize;
clAddrSize = sizeof(clAddr);
clSocket.shared->sockFd = ::accept(shared->sockFd, (struct sockaddr *)&clAddr, &clAddrSize);
if (clSocket.shared->sockFd < 0) {
printf("failed to accept incoming connection (code: %d)\n", WSAGetLastError());
throw SocketException(6, "failed to accept incoming connection");
}
clSocket.shared->buffer = new byte [BUFFER_SIZE];
clSocket.shared->curPos = clSocket.shared->endPos = clSocket.shared->buffer;
return clSocket;
}
但是在调用 accept() 之后我得到了
failed to accept incoming connection (code: 10014)
根据 MSDN:
WSAEFAULT 10014 地址不好。 系统在尝试使用调用的指针参数时检测到无效的指针地址。如果应用程序发生此错误 传递了一个无效的指针值,或者缓冲区的长度太长 小的。例如,如果参数的长度是 sockaddr 结构,小于 sizeof(sockaddr)。
我不明白,这些指针是怎么坏的,它们都直接寻址一个局部变量。 clAddrSize 被初始化,shared->sockFd 在另一个函数中被初始化
void TCPSocket::listen(uint16_t port, int backlog) {
struct addrinfo * ainfo;
char portStr[8];
int res;
if (shared->sockFd != -1)
logicError(1, "socket already initialized, need to close first");
snprintf(portStr, sizeof(portStr), "%hu", (ushort)port);
if (getaddrinfo("localhost", portStr, NULL, &ainfo) != 0)
systemError(2, "failed to retrieve info about localhost", false);
shared->sockFd = socket(ainfo->ai_family, SOCK_STREAM, IPPROTO_TCP);
if (shared->sockFd < 0)
systemError(3, "failed to create a TCP socket", false);
res = bind(shared->sockFd, ainfo->ai_addr, ainfo->ai_addrlen);
if (res != 0)
systemError(5, "failed to bind socket to local port", true);
res = ::listen(shared->sockFd, backlog);
if (res != 0)
systemError(6, "failed to set socket to listen state", true);
freeaddrinfo(ainfo);
}
你看到我忽略了什么吗?
【问题讨论】:
-
闻起来像损坏的内存管理,在调用
accept()之前发生(方式)。 -
socklen_t和accepts()的最后一个参数(由您使用的 API 定义)大小是否匹配? -
typedef int socklen_t; WINSOCK_API_LINKAGE SOCKET PASCAL 接受(SOCKET,struct sockaddr*,int*);所以是的,它是一样的
-
你也有机会在 IPv6 上收听吗?
accept调用返回一个 IPv6 套接字 (struct sockaddr_in6),它太大而无法放入struct sockaddr_in变量?为了便于携带,应该使用struct sockaddr_storage。 -
@Youda008:那肯定会落入@987654333的“...缓冲区的长度太小 ...”子句中@。如果您不准备正确处理 IPv6,另一种方法是通过
hints参数将getaddrinfo()限制为 IPv4。
标签: c++ c networking tcp winsock2