【问题标题】:Linux sockets & threadingLinux 套接字和线程
【发布时间】:2019-04-24 20:02:26
【问题描述】:

我正在 Linux 上编写一些 TCP 服务器代码,它正在为带有 buildroot 工具链的 Pi 进行交叉编译。基本上我接受一个套接字然后创建一个线程来监听数据并处理它。为了测试,我使用 telnet 作为客户端。有时,当套接字关闭时,程序在线程清理期间崩溃,我不知道为什么。我最好的猜测是文件描述符的怪异,但目前这主要是猜测。

代码如下:

void NetworkControl::startListening()
{
    mListenThread = std::thread(listener);
    mListenThread.detach();
}

void NetworkControl::listener()
{
    int sockfd, newsockfd, clilen;
    struct sockaddr_in serv_addr, cli_addr;

    int portno = 612;

    std::thread mWorkThread;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
       {} //print error

    bzero((char *) &serv_addr, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);
    if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
    { }//print error

    listen(sockfd,5);

    clilen = sizeof(cli_addr);

    while (1) { 
        newsockfd = accept(sockfd, 
            (struct sockaddr *) &cli_addr, (socklen_t*) &clilen);
        if (newsockfd < 0) {
            //print error
        }else{
            mWorkThread = std::thread(worker,newsockfd);
            mWorkThread.detach();
        }
    }
}

void NetworkControl::worker(int sock)
{
    uint32_t n;

    char *buf = new char(200);

    while(1){
        n = read(sock,&buf[0],199);;
        if (n <= 0){
            goto exit;
        }
        buf[n] = '\x00';
        printf("%s\n",buf);
    }
    exit:
    free(buf);
    close(sock);
}

这是崩溃的回溯:

#0  0x767c4e0c in raise () from /home/david/Desktop/BR-Pi2/output/host/arm-buildroot-linux-gnueabihf/sysroot/lib/libc.so.6
#1  0x767c60e4 in abort () from /home/david/Desktop/BR-Pi2/output/host/arm-buildroot-linux-gnueabihf/sysroot/lib/libc.so.6
#2  0x767fe2c8 in __libc_message () from /home/david/Desktop/BR-Pi2/output/host/arm-buildroot-linux-gnueabihf/sysroot/lib/libc.so.6
#3  0x76804790 in malloc_printerr () from /home/david/Desktop/BR-Pi2/output/host/arm-buildroot-linux-gnueabihf/sysroot/lib/libc.so.6
#4  0x76805850 in _int_free () from /home/david/Desktop/BR-Pi2/output/host/arm-buildroot-linux-gnueabihf/sysroot/lib/libc.so.6
#5  0x768a3c78 in tcache_thread_freeres () from /home/david/Desktop/BR-Pi2/output/host/arm-buildroot-linux-gnueabihf/sysroot/lib/libc.so.6
#6  0x768a3cdc in __libc_thread_freeres () from /home/david/Desktop/BR-Pi2/output/host/arm-buildroot-linux-gnueabihf/sysroot/lib/libc.so.6
#7  0x76f01f3c in start_thread () from /home/david/Desktop/BR-Pi2/output/host/arm-buildroot-linux-gnueabihf/sysroot/lib/libpthread.so.0
#8  0x768683b8 in ?? () from /home/david/Desktop/BR-Pi2/output/host/arm-buildroot-linux-gnueabihf/sysroot/lib/libc.so.6
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

控制台输出:

free() invalid next size (fast)

如果有人有任何想法,我将不胜感激!

【问题讨论】:

  • 我假设NetworkControl::listenerstatic 成员函数?您可以尝试创建一个minimal reproducible example 向我们展示吗?
  • 至于您收到的消息,通常是在您写入超出分配内存的范围时。使用例如Valgrind 帮助您了解更多信息。
  • 提示:new char(200) 分配了一个single char,并将其初始化为值200
  • 此外:始终将newdelete 匹配,将new[]delete[] 匹配。也许您应该退后几步,find a good book or two 并阅读有关动态内存分配的更多信息(以及更多有关 IMO 的内容)?或者更好的是,对所有字符串使用std::string
  • 最后,永远不要使用goto 和标签。如果您需要跳出循环,请使用break

标签: c++ linux multithreading sockets


【解决方案1】:

正如其他人已经告诉过的那样,崩溃是由将 new() 与 free() 配对引起的,而您实际上需要 new[]/delete[]。

但是,使用std::vector,您甚至不必自己进行内存分配。 (示例代码未编译/测试)

void NetworkControl::worker(int sock)
{
    uint32_t n;

    std::vector<char> buf(200);

    while(1){
        n = read(sock, buf.data(), 199);
        if (n <= 0){
            break;
        }
        buf[n] = '\x00';
        printf("%s\n",buf.data());
    }
    close(sock);
}

对于buf,您也可以使用C 样式数组或std::array&lt;char&gt;,但是您必须确保不会出现stackoverflow。

【讨论】:

    【解决方案2】:

    free() 函数释放 ptr 指向的内存空间,该内存空间必须由先前对 malloc()、calloc() 或 realloc() 的调用返回。其他- 明智的,或者如果之前已经调用过 free(ptr),则会发生未定义的行为。如果 ptr 为 NULL,则不执行任何操作。

    但在您的代码上下文中:

    char *buf = new char(200);

    指针是由新函数获取的,它是一个 C++ 函数,这就是你的程序崩溃的原因。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-02
      • 1970-01-01
      • 2011-11-26
      • 2011-11-14
      • 2011-02-11
      • 2013-04-02
      • 2015-05-21
      • 1970-01-01
      相关资源
      最近更新 更多