donatello1996 发表于 2018-12-19 09:26

【树莓派3B+测评】TCP客户端&阻塞线程创建&取消

本帖最后由 donatello1996 于 2018-12-19 09:30 编辑

【树莓派3B+测评】TCP客户端&阻塞线程创建&取消


    在Linux系统中,TCP通信还有一个常用角色是客户端,像树莓派这种板子,经常充当从机角色连接电脑主机,在这种情况下,以客户端身份连接主机是比较易于理解且占用资源较少的做法,主机的服务器一直开着,树莓派从机可按需分时进行TCP连接或者一直检测主机服务器是否掉线以确保通信的稳定,那么,在上一帖中提到过,TCP通信要同时收发且互不干扰,必须开启多一个用于发送的线程,当TCP连接断开的时候,这个线程要挂起或者取消,在频繁的客户端连接主机的过程中,自然也就会频繁地开启或关闭TCP发送线程,这就涉及到线程里面最简单的创建和取消操作。
    首先让树莓派以客户端身份连接电脑主机TCP服务器,非常简单,只需要用到socket()和connect()两个函数:
      socklen_t addrsize=sizeof(struct sockaddr);
      struct sockaddr_in girladdr;
      bzero(&girladdr,sizeof(girladdr)); // 清零
      girladdr.sin_family=AF_INET;
      girladdr.sin_port=htons(10086); //host-->network
      girladdr.sin_addr.s_addr=inet_addr("169.254.122.1");
        connect(fd_socket,(struct sockaddr *)&girladdr,addrsize);

如果是做一个循环检测主机TCP服务器是否存在的算法,就使用三个while循环即可:
      while(1)
      {
            while(1)
            {
                fd_socket=socket(AF_INET,SOCK_STREAM,0);
                if(fd_socket==-1)
                {
                        printf("套接字初始化失败!\n");
                        return -1;
                }
                ret=connect(fd_socket,(struct sockaddr *)&girladdr,addrsize);
                if(ret==0)
                {
                  printf("与服务器建立连接\n");
                  break;
                }
            }
            while(1)
            {
                bzero(recvbuf,100);
                ret=recv(fd_socket,recvbuf,100,0);
                if(ret==0)
                {
                  printf("与服务器失去连接\n");
                  break;
                }
                printf("服务器端发来信息:%s\n",recvbuf);
            }
      }

另外,还要开辟一个用于TCP输入字符串发送的线程,与上一帖一样:
int fd_socket;
pthread_t id1;
unsigned char sendbuf,recvbuf;

void *Thread_Send_buf(void *arg)
{
    int len;
    while(1)
    {
      bzero(sendbuf,100);
      scanf("%s",sendbuf);
      //printf("----\n");
      for(len=0;sendbuf!='\0';len++);
      //printf("%d\n",Raspi_DHT11_Read());
      send(fd_socket,sendbuf,len,0);
    }
}

要将线程的建立&取消和TCP客户端循环连接服务器的代码结合起来用,才可以实现本帖的功能:
int fd_socket;
pthread_t id1;
unsigned char sendbuf,recvbuf;

void *Thread_Send_buf(void *arg)
{
    int len;
    while(1)
    {
      bzero(sendbuf,100);
      scanf("%s",sendbuf);
      for(len=0;sendbuf!='\0';len++);
      send(fd_socket,sendbuf,len,0);
    }
}

int main()
{
        int i=0;
      int ret=-1;

      socklen_t addrsize=sizeof(struct sockaddr);
      struct sockaddr_in girladdr;
      bzero(&girladdr,sizeof(girladdr)); // 清零
      girladdr.sin_family=AF_INET;
      girladdr.sin_port=htons(10086); //host-->network
      girladdr.sin_addr.s_addr=inet_addr("169.254.122.1");

      int thread_1=0;
      while(1)
      {
            while(1)
            {
                fd_socket=socket(AF_INET,SOCK_STREAM,0);
                if(fd_socket==-1)
                {
                        printf("套接字初始化失败!\n");
                        return -1;
                }
                ret=connect(fd_socket,(struct sockaddr *)&girladdr,addrsize);
                if(ret==0)
                {
                  printf("与服务器建立连接\n");
                  ret=pthread_create(&id1,NULL,Thread_Send_buf,NULL);
                  if(ret==0)
                        printf("TCP发送阻塞线程被创建\n");
                  break;
                }
            }
            while(1)
            {
                bzero(recvbuf,100);
                ret=recv(fd_socket,recvbuf,100,0);
                if(ret==0)
                {
                  printf("与服务器失去连接\n");
                  ret=pthread_cancel(id1);
                  if(ret==0)
                        printf("TCP发送阻塞线程被取消\n");
                  break;
                }
                printf("服务器端发来信息:%s\n",recvbuf);
            }
      }
}

看看效果,运行程序之后,树莓派会一直检测主机的TCP服务器是否开启,如果开启了就连接,并可正常使用TCP收发:

如果主机主动断开连接,那么树莓派端一样会检测到:

如果主机再次开启TCP服务器,那么树莓派会在十几秒之后重新握手建立连接:

至于为什么是十几秒呢,这个据以前的Linux大佬说,TCP端口重新开启需要十几秒的时间。

即使连接是断开之后再建立的,仍可正常收发:


页: [1]
查看完整版本: 【树莓派3B+测评】TCP客户端&阻塞线程创建&取消