从套接字接收线程中的消息

Posted

技术标签:

【中文标题】从套接字接收线程中的消息【英文标题】:Receving message in thread from socket 【发布时间】:2015-10-15 09:17:00 【问题描述】:

我正在编写一个套接字程序并在一个线程中接收一条消息。但是我遇到了分段错误。 当我直接接收而不启动线程时,没有这样的问题(显示在注释部分)。

在下面的代码中,我直接接收并将其发送给客户端。部分代码如下所示:

if (acceptor->start() == 0)
    
        while (1)
        
            stream = acceptor->accept();
            if (stream != NULL)
            
                /*
                ssize_t len;
                char line[256];
                while ((len = stream->receive(line, sizeof(line))) > 0) 
                    line[len] = 0;
                    printf("received - %s\n", line);
                    stream->send(line, len);
                */    
                pthread_t sniffer_thread;
                if( pthread_create( &sniffer_thread, NULL, connection_handler,NULL) < 0)
                
                     perror("could not create thread");
                     return 1;
                
                //Now join the thread , so that we dont terminate before the thread
                pthread_join( sniffer_thread , NULL);
             
                delete stream;
          
       
    exit(0);

现在,我在线程函数中收到了相同的信息。它显示分段错误。

代码如下所示。

void *connection_handler(void *arg)

    TCPStream* stream = NULL;
    ssize_t len;
    char line[256];
    while ((len = stream->receive(line, sizeof(line))) > 0)
    
        line[len] = 0;
        printf("received - %s\n", line);
        stream->send(line, len);
    

Valgrind 输出的一部分是

==5163== Memcheck, a memory error detector
==5163== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==5163== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==5163== Command: ./appdownload 9999 192.5.60
==5163== 
==5163== Thread 2:
==5163== Invalid read of size 4
==5163==    at 0x401975: TCPStream::receive(char*, unsigned long, int) (tcpstream.cpp:30)
==5163==    by 0x40177B: connection_handler(void*) (appdownload.cpp:68)
==5163==    by 0x4E3F181: start_thread (pthread_create.c:312)
==5163==    by 0x566947C: clone (clone.S:111)
==5163==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==5163== 
==5163== 
==5163== Process terminating with default action of signal 11 (SIGSEGV)
==5163==  Access not within mapped region at address 0x0
==5163==    at 0x401975: TCPStream::receive(char*, unsigned long, int) (tcpstream.cpp:30)
==5163==    by 0x40177B: connection_handler(void*) (appdownload.cpp:68)
==5163==    by 0x4E3F181: start_thread (pthread_create.c:312)
==5163==    by 0x566947C: clone (clone.S:111)
==5163==  If you believe this happened as a result of a stack
==5163==  overflow in you`enter code here`r program's main thread (unlikely but
==5163==  possible), you can try to increase the size of the
==5163==  main thread stack using the --main-stacksize= flag.
==5163==  The main thread stack size used in this run was 8388608.

【问题讨论】:

调试器说什么? 具体是什么指令给出了分段错误? 显示 valgrind 输出。 虽然解决了NULL流的问题,但我想知道您是否需要删除流指针。我还建议使用 C++ 线程构造而不是 pthread。 【参考方案1】:
TCPStream* stream = NULL; // HERE
ssize_t len;
char line[256];
while ((len = stream->receive(line, sizeof(line))) > 0) // HERE

您在 NULL 指针上调用 receive。 Valgrind 告诉你:

==5163== Thread 2:
==5163== Invalid read of size 4
==5163==    at 0x401975: TCPStream::receive(char*, unsigned long, int) (tcpstream.cpp:30) // HERE
==5163==    by 0x40177B: connection_handler(void*) (appdownload.cpp:68)
==5163==    by 0x4E3F181: start_thread (pthread_create.c:312)
==5163==    by 0x566947C: clone (clone.S:111)
==5163==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
              //  ^- HERE

如果你需要将TCPStream*从主线程传递给新的线程函数,你可以使用pthread_create的第四个参数:

pthread_create() 函数在调用中启动一个新线程 过程。新线程通过调用 start_routine() 开始执行; arg 作为 start_routine() 的唯一参数传递。 (来源:man pthread_create

主线程:

TCPStream *stream = acceptor->accept();
(...)
pthread_create( &sniffer_thread, NULL, connection_handler, stream)
                                                      //   ^^^^^^

工作线程:

void *connection_handler(void *arg)

    TCPStream* stream = (TCPStream *)arg;
    //                  ^^^^^^^^^^^^^^^^

【讨论】:

谢谢。那么我需要如何声明 TCPStream *stream 对象 .Globally? @user2357643 全局或(最好)将其作为第四个参数传递给pthread_create 我将它作为第四个参数传递。现在显示为警告:valgrind 的系统调用 read() 中的文件描述符 96707392 无效并且无法接收消息。但现在没有分段错误【参考方案2】:

在显示 valgrind 跟踪之后,很明显您只是在空指针上调用 receive


嗯,让我们看看。

char line[256];                                              // 256 bytes space
while ((len = stream->receive(line, sizeof(line))) > 0)      // receive up to 256 bytes

    line[len] = 0;                                           // put 257th byte in

我想您可以为 0 多使用一个字节 - 尝试接收最多 sizeof(line)-1

或者只使用std::vector 然后push_back 那个0。

【讨论】:

@user2357643:这是因为“直接”代码有一个指向 stream 对象的非 NULL 指针(由 accept() 返回),而 connection_handler 代码已初始化它的同名变量streamNULL。这两个变量没有自动连接,-&gt;receive() 调用使用它正在执行的范围内可见的任何一个。

以上是关于从套接字接收线程中的消息的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin/WinForms 客户端在双线程架构中发送/接收时无法连接到套接字

从套接字接收消息时,Vue.js 数据未更新

从不同线程在同一个套接字上发送和接收不起作用

erlang:如何从套接字接收 HTTP/RTSP 消息?

Java 套接字:您可以从一个线程发送并在另一个线程上接收吗?

带有线程池服务器python的套接字