【问题标题】:how to create thread for recieving data如何创建接收数据的线程
【发布时间】:2015-06-21 07:55:48
【问题描述】:
tcp_socket()
{
      sock = socket(AF_INET , SOCK_STREAM , 0);

      if (sock == -1)
      {
          printf("Could not create socket\n");
      }
      puts("Socket created.......\n");

      server.sin_addr.s_addr = inet_addr("172.210.110.10");
      server.sin_family = AF_INET;
      server.sin_port = htons(PORT);

      //Connect to remote server
      con= connect(sock , (struct sockaddr *)&server , sizeof(server));

      if(con<0)
      {
          perror("connect failed. Error\n");
          return con;
      }

      puts("Connected\n");

      err = pthread_create(&tid, NULL,reciever_port,(int*)sock);
                  if (err != 0)
          printf("\ncan't create thread :[%s]", strerror(err));
                  else
          printf("\n Thread created successfully\n");


      return 1;
  }


  void *reciever_port(int sockid)
  {
        unsigned char inbuf[MAX_REQUEST_LINES]="";

        while(1)
        {
            memset(inbuf, 0, sizeof(inbuf));
            rc=recv(sockid , inbuf , 1024 , 0);

            if(rc<0)
            {
                puts("waiting .........\n");
                exit(0);
            }
            else
            {
                for(i=0;i<rc;i++)
                {
                    printf("%c",inbuf[i]);
                }   
            }

我已经打开了一个客户端套接字并使用pthread_create 调用函数reciever_port,其中reciever_port 一个while 循环不断接收,如果任何数据来自服务器,但它没有打印任何东西,无法正常工作,而没有线程它正在工作。

我错过了什么,或者有人可以指出我正确的方向吗?

【问题讨论】:

  • 如果你将(int*)作为参数传递给线程,你应该得到int*作为参数:void *reciever_port(void* arg) { int sockid = * (int*) arg; ...
  • @myaut 这有点邪恶,因为sizeof int 不一定是sizeof void *
  • 我认为这是线程启动的问题,请确保您将参数正确传递给线程函数。换句话说,接收数据不是问题,您应该暂时忽略它。在这种情况下要查看的另一件事是sock 的范围:上面,它看起来像是全局的!
  • @dhke,哦,我没注意到他没有取sock的地址,而是直接传了。

标签: c linux sockets pthreads


【解决方案1】:

你有一个指针转换问题:

  err = pthread_create(&tid, NULL,reciever_port,(int*)sock);

这会将sock 整数的值转换为int * 指针。无法保证这实际上适用于所有平台(这就是为什么通常会有 intptr_t *

这一行也应该引发编译器警告,因为reciever_port 的类型是

void *(*reciever_port)(int sockid);

而线程函数的类型是

void *(*start_routine)(void *);

我有点惊讶这实际上可以编译。您确实启用了警告,对吗?

reciever_port() 中,您将 void *-disguised int 隐式转换回整数,但也不能保证有效。

稍微清理一下:

  int *thread_socket = calloc(1, sizeof(int));
  *thread_socket = sock;
  err = pthread_create(&tid, NULL,reciever_port,thread_socket);
  if (err != 0) { 
      free(thread_socket);
      [...]
  }
  [...]



  void *reciever_port(void *arg)
  {
       int socket = *(int *)arg;
       free(arg);
       [...]

请注意,我对这段代码中的“被调用者释放调用者分配的内存”不太满意。

sock 是一个不能消失的静态变量时,可以避免alloc-free-dance,但这样你实际上可以创建多个线程。如果sock 是一个全局变量,则根本无需费心将其作为参数传递。

您的线程代码可能还需要一些额外的工作:

void *
reciever_port(int sockid)
{
     // MAX_REQUEST_LINES might be a misnomer, you don't read lines,
     // you read individual bytes/chars.
     unsigned char inbuf[MAX_REQUEST_LINES] = "";      

     while(1) {
         memset(inbuf, 0, sizeof(inbuf));
         // you really don't want 1024 as a magic number, here
         rc = recv(sockid, inbuf, sizeof(inbuf) ,0);

         if (rc < 0) {
             perror("Error receiving data: ");
             /* no need to kill everything when the thread exits */
             return NULL;
         } else {
             for(i = 0;i < rc; i++) {
                 putc(inbuf[i]);
             }
             fflush(stdout);
         }
    }
}

注意输出流的显式fflush()。否则您可能看不到任何输出,因为 stdout 通常是行缓冲的,因此每次没有换行的写入都会保留在内存中,直到缓冲区满为止。

【讨论】:

  • 我实现了上面给出的代码,代码没有错误,但是线程没有感知数据。我在线程 plz 指南中犯了一些错误
  • 您是否真的没有得到任何数据,或者只是缓冲输出,因为您在没有换行符的情况下执行printf() 后从未发出fflush()?另外:有什么理由不使用putc()
  • lol '请注意,我对这段代码中的“被调用者释放调用者分配的内存”不太满意。 ' - 由于指针被复制到另一个堆栈,我看不到任何绕过它的方法。在编写多线程代码时,您要么必须接受必须丢弃一些可疑的范例,要么会陷入真正的混乱。在进程终止之前清理内存分配也必须去。提倡这种做法的人是那些从未真正编写过任何复杂的多线程应用程序的人,或者如果他们写过,这些应用程序存在“问题”。
  • @MartinJames 这就是为什么它“不太高兴”,意思是“这违反了我的一般规则之一,所以我正在努力确保它可以正常工作”;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-04
  • 1970-01-01
  • 2018-08-11
  • 2012-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多