gpt4 book ai didi

c - 拆分 TCP 流上的 Winsock2 错误 10014

转载 作者:可可西里 更新时间:2023-11-01 02:47:17 24 4
gpt4 key购买 nike

先写代码

DWORD WINAPI tcp_t(LPVOID lpParam)
{
SOCKET tcp_client_s = (SOCKET)lpParam;
struct sockaddr_in tcp_client;
int tcp_client_len = sizeof(tcp_client), length;
char req[4096], resp[4096];

getpeername(tcp_client_s, (struct sockaddr *)&tcp_client, &tcp_client_len);

cli_log(PROTO_TCP, LOG_SYS, "(%s:%d) TCP thread spawned\n", inet_ntoa(tcp_client.sin_addr), ntohs(tcp_client.sin_port));

length = get_req_tcp(tcp_client_s, req, tcp_client);

if(strci(req, "GET /syachi2ds/web/", 0))
{
while(!strstr(req, "Connection: close\r\n\r\n"))
length += get_req_tcp(tcp_client_s, req + length, tcp_client);

length = check_req(req, resp);

if(length > 0)
send_resp_tcp(tcp_client_s, resp, length, tcp_client);
}

closesocket(tcp_client_s);
cli_log(PROTO_TCP, LOG_SYS, "(%s:%d) socket closed, closing thread\n", inet_ntoa(tcp_client.sin_addr), ntohs(tcp_client.sin_port));
ExitThread(0);
}

int get_req_tcp(SOCKET in_s, char *buf, struct sockaddr_in in)
{
int retval;

cli_log(PROTO_TCP, LOG_COMM, "(%s:%d) waiting for incoming request...\n", inet_ntoa(in.sin_addr), ntohs(in.sin_port));
if ( (retval = recv(in_s, buf, 4096, 0)) == SOCKET_ERROR)
cli_log(PROTO_TCP, LOG_ERROR, "(%d) recv() failed\n", WSAGetLastError());
cli_log(PROTO_TCP, LOG_COMM, "(%s:%d) data received\n", inet_ntoa(in.sin_addr), ntohs(in.sin_port));
return retval;
}

这是我正在编写的一个大型程序的一部分,该程序执行某种服务器模拟。它适用于未拆分为多个数据包的 TCP 流,否则它会在 while 循环中调用的第一个后续 recv() 中给出 winsock 错误 10014。

PS:strci()是自定义的不区分大小写的strstr()

PS2:我知道没有检查 req 数组上的缓冲区溢出。

最佳答案

10014 是 WSAEFAULT,这意味着 recv() 检测到“buf 参数未完全包含在用户地址空间的有效部分中”。这是有道理的,因为您的代码中存在缓冲区溢出错误。您已在调用堆栈上为您的 req 缓冲区分配了 4096 字节。每次调用 get_req_tcp() 时,您都在告诉它读取 4096 字节,即使 req 实际上没有 4096 字节可供读取。

每次循环运行时,您都在告诉 recv() 将字节读入缓冲区内的新起始位置,但您没有告诉 recv() 如何读取字节在该位置之后还有许多字节,因此循环溢出缓冲区并最终访问不在调用堆栈上的内存地址,从而导致 WSAEFAULT 错误。

您需要向 get_req_tcp() 添加一个额外参数,告诉它要读取多少字节。

试试这个:

DWORD WINAPI tcp_t(LPVOID lpParam)
{
SOCKET tcp_client_s = (SOCKET)lpParam;
struct sockaddr_in tcp_client;
int tcp_client_len = sizeof(tcp_client), length;
char req[4096], resp[4096];

getpeername(tcp_client_s, (struct sockaddr *)&tcp_client, &tcp_client_len);

cli_log(PROTO_TCP, LOG_SYS, "(%s:%d) TCP thread spawned\n", inet_ntoa(tcp_client.sin_addr), ntohs(tcp_client.sin_port));

length = get_req_tcp(tcp_client_s, req, sizeof(req), tcp_client);
if (length > 0)
{
while (!strstr(req, "\r\n\r\n"))
{
retval = get_req_tcp(tcp_client_s, req + length, sizeof(req) - length, tcp_client);
if (retval < 1)
{
length = 0;
break;
}
length += retval;
}

if ((length > 0) && (strci(req, "GET /syachi2ds/web/", 0)))
{
length = check_req(req, resp);
if (length > 0)
send_resp_tcp(tcp_client_s, resp, length, tcp_client);
}
}

closesocket(tcp_client_s);
cli_log(PROTO_TCP, LOG_SYS, "(%s:%d) socket closed, closing thread\n", inet_ntoa(tcp_client.sin_addr), ntohs(tcp_client.sin_port));

return 0;
}

int get_req_tcp(SOCKET in_s, char *buf, int buflen, struct sockaddr_in in)
{
cli_log(PROTO_TCP, LOG_COMM, "(%s:%d) waiting for incoming request...\n", inet_ntoa(in.sin_addr), ntohs(in.sin_port));

if ((!buf) || (buflen < 1))
{
cli_log(PROTO_TCP, LOG_ERROR, "invalid buffer passed for recv()\n");
return -1;
}

int retval = recv(in_s, buf, buflen, 0);

if (retval == SOCKET_ERROR)
{
cli_log(PROTO_TCP, LOG_ERROR, "(%d) recv() failed\n", WSAGetLastError());
return -1;
}

if (retval == 0)
{
cli_log(PROTO_TCP, LOG_ERROR, "client disconnected\n");
return 0;
}

cli_log(PROTO_TCP, LOG_COMM, "(%s:%d) %d bytes received\n", retval, inet_ntoa(in.sin_addr), ntohs(in.sin_port));

return retval;
}

关于c - 拆分 TCP 流上的 Winsock2 错误 10014,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14123184/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com