我编写了一个连接到 TCP 服务器、发送字符串并接收字符串回复的函数。还有一个定义为字符数组的缓冲区,每次都会被清除并填充来自套接字的字符串回复。 这个函数被我的程序中的多个pthread同时调用。问题是它工作正常,但几分钟后,程序崩溃并出现信号11(SIGSEGV)。你能帮我吗?另外,如果有更好的实现,如果您分享,我将不胜感激。
int software::send_tcp_remote_cmd(std::string inputstr, std::string *outputstr, short timeout)
{
char *serverIp = (char *)config["common"]["rch_ip"].get<std::string>().c_str();
int port = config["common"]["rch_port"].get<int>();
// create a message buffer
char msg[3500] = {'\0'};
// setup a socket and connection tools
struct hostent *host = gethostbyname(serverIp);
sockaddr_in sendSockAddr;
bzero((char *)&sendSockAddr, sizeof(sendSockAddr));
sendSockAddr.sin_family = AF_INET;
sendSockAddr.sin_addr.s_addr =
inet_addr(inet_ntoa(*(struct in_addr *)*host->h_addr_list));
sendSockAddr.sin_port = htons(port);
int clientSd = socket(AF_INET, SOCK_STREAM, 0);
struct timeval tv;
tv.tv_sec = timeout;
tv.tv_usec = 0;
setsockopt(clientSd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv);
// try to connect...
int status = connect(clientSd,
(sockaddr *)&sendSockAddr, sizeof(sendSockAddr));
if (status < 0)
{
cout << "send_tcp_remote_cmd : Error connecting to socket!" << endl;
return -1;
}
int bytesRead = 0;
int bytesWritten = 0;
memset(&msg, 0, sizeof(char)*3500); // clear the buffer
strcpy(msg, inputstr.c_str());
spdlog::get("debug")->debug(">>>>>>>>TCP sending : {}", inputstr);
bytesWritten += send(clientSd, (char *)&msg, strlen(msg), 0);
spdlog::get("debug")->debug("Awaiting server response...");
memset(&msg, 0, sizeof(char)*3500); // clear the buffer
bytesRead += recv(clientSd, (char *)&msg, sizeof(msg), 0);
if (bytesRead > 0 && msg[0] != '\0' && outputstr !=NULL)
{
spdlog::get("debug")->debug("Server: {}", std::string(msg));
*outputstr = std::string(msg);
}
spdlog::get("debug")->debug("Bytes written: {} Bytes read: {}", bytesWritten, bytesRead);
if(bytesRead == 0)
{
close(clientSd);
return 0;
}
if (bytesRead == -1) {
switch (errno) {
case EAGAIN:
perror("Failed to read from socket: code = EAGAIN");
close(clientSd);
break;
default:
perror("Failed to read from socket");
close(clientSd);
break;
}
return -2;
}
close(clientSd);
return 0;
}
这是堆栈跟踪:
--- command='' signal=11 date='29/08/2024 16:45:10' ---
./backend(+0x115207) [0x561998dcb207]
/lib/x86_64-linux-gnu/libc.so.6(+0x3ef10) [0x7f4530a03f10]
./backend(_ZN7backend8software19send_tcp_remote_cmdENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPS6_s+0x10b) [0x561998fa2abb]
./backend(_ZN7backend8software20get_disk_utilizationENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE+0x125) [0x561998fa5be5]
./backend(+0x18053e) [0x561998e3653e]
./backend(_ZN7httplib6Server7routingERNS_7RequestERNS_8ResponseERNS_6StreamE+0x580) [0x561998e171d0]
./backend(_ZN7httplib6Server15process_requestERNS_6StreamEbRbRKSt8functionIFvRNS_7RequestEEE+0xac2) [0x561998e18762]
./backend(_ZN7httplib9SSLServer24process_and_close_socketEi+0x49b) [0x561998e191db]
./backend(_ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJN7httplib10ThreadPool6workerEEEEEE6_M_runEv+0x150) [0x561998ebba10]
/usr/lib/x86_64-linux-gnu/libstdc++.so.6(+0xe067f) [0x7f453145767f]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x76db) [0x7f453262c6db]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x3f) [0x7f4530ae661f]
我认为这可能是由不正确的 memset() 引起的,但事实并非如此。
那么,如果
inputstr
的长度等于或大于神奇的3500(msg
的大小)怎么办?
strcpy(msg, inputstr.c_str());
您写入随机内存(本地堆栈,这可能很长一段时间不可见)。
如果接收到的数据恰好等于神奇的 3500 (
sizeof(msg)
) 怎么办?
bytesRead += recv(clientSd, (char *)&msg, sizeof(msg), 0);
\0
末尾的哨兵msg
被消灭。因此,在复制到 std::string
函数clone
时会出现段错误。