如何创建用于接收数据的线程

时间:2015-06-21 07:55:48

标签: c linux sockets pthreads

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]);
                }   
            }

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

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

1 个答案:

答案 0 :(得分:2)

您有指针转换问题:

  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 * - 伪装的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);
       [...]

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

sock是一个无法消失的静态变量时,可以避免无分配舞蹈,但这样你实际上可以创建多个线程。如果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通常是行缓冲的,因此每个没有换行的写操作都会保留在内存中,直到缓冲区已满。