1. 程式人生 > >25、新手入手樹莓派教程--通過TCP遠端控制GPIO(C++)

25、新手入手樹莓派教程--通過TCP遠端控制GPIO(C++)

一、分析

1、GPIO口初始化藉助wiringPi;

2、利用linux下socket中的API,進行TCP通訊

二、一個服務端和一個客戶端

1、server端

//
/************************************************************************* 
    > File Name: server.c 
    > Author: Sen 
    > Date: 2018-5-8 
 ************************************************************************/  
  
#include <stdio.h>  
#include <string.h>  
#include <stdlib.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <sys/un.h>  
#include <arpa/inet.h>  
#include <netinet/in.h> 
#include <wiringPi.h>
#include <wiringSerial.h> 
  
const int port = 8888;  
const char* ip = "192.168.1.88";   
  
int main()  
{  
      //建立套接字,即建立socket   
      int ser_sock = socket(AF_INET, SOCK_STREAM, 0);   
      if(ser_sock < 0)  
      {  
          //建立失敗  
          perror("socket");  
          return 1;  
      }  
  
      //繫結資訊,即命名socket   
      struct sockaddr_in addr;   
      addr.sin_family = AF_INET;   
      addr.sin_port = htons(port);   
      //inet_addr函式將用點分十進位制字串表示的IPv4地址轉化為用網路   
      //位元組序整數表示的IPv4地址   
      addr.sin_addr.s_addr = inet_addr(ip);   
      if(bind(ser_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)   
      {               
           //命名失敗   
           perror("bind");   
           return 2;         
      }   
  
      //監聽socket  
      int listen_sock = listen(ser_sock, 5);  
      if(listen_sock < 0)  
      {  
          //監聽失敗  
          perror("listen");  
          return 3;  
      }  
  
      //接受連線  
      //系統呼叫從listen監聽佇列中接受一個連線  
      //int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen)  
      //sockfd引數是執行過listen系統呼叫的監聽socket;addr引數用來獲取被  
      //接受連線的遠端socket地址,該socket地址的長度由addrlen引數指出  
      //accept成功時返回一個新的連線socket,該socket唯一的標識了被接受  
      //的這個連線,伺服器可通過讀寫該socket來與被接受連線對應的客戶端通訊  
      struct sockaddr_in peer;  
      socklen_t peer_len;  
      char buf[1024];  
      int accept_fd = accept(ser_sock, (struct sockaddr*)&peer, &peer_len);  
  
      if(accept_fd < 0)  
      {  
          perror("accept");  
          return 4;  
      }  
      else  
      {  
          printf("connected with ip: %s  and port: %d\n", inet_ntop(AF_INET,&peer.sin_addr, buf, 1024), ntohs(peer.sin_port));  
          
      }  
      wiringPiSetup();
      pinMode(0, OUTPUT);
      while(1)  
      {  
          memset(buf, '\0', sizeof(buf));  
          ssize_t size = read(accept_fd, buf, sizeof(buf) - 1);  
          if (size > 0)  
          {  
              printf("client#: %s\n", buf);
	      if (size = 1)
              {   
                  //control GPIO.0
                  int tmp = atoi(buf);
                  if (tmp == 1)
	          {
                      digitalWrite(0, HIGH);
                  } else {
                      digitalWrite(0, LOW);
                  }
              }  
          }
          else if(size == 0)  
          { 
              digitalWrite(0, LOW); 
              printf("read is done...\n");  
              //break;  
          }  
          else   
          {  
              digitalWrite(0, LOW);
              perror("read");  
              //break;  
          }  
      }  
        close(ser_sock);  
      return 0;  
}  
//

2、client端

//
/************************************************************************* 
    > File Name: client.c 
    > Author: Sen  
    > Date: 2018-5-8 
 ************************************************************************/  
  
#include <stdio.h>  
#include <string.h>  
#include <stdlib.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <sys/un.h>  
#include <arpa/inet.h>  
#include <netinet/in.h>  
  
const int port = 8888;  
const char* ip = "192.168.1.88";   
  
int main()  
{  
      //建立套接字,即建立socket   
      int clt_sock = socket(AF_INET, SOCK_STREAM, 0);   
      if(clt_sock < 0)  
      {  
          //建立失敗  
          perror("socket");  
          return 1;  
      }  
  
      //繫結資訊,即命名socket   
      struct sockaddr_in addr;   
      addr.sin_family = AF_INET;   
      addr.sin_port = htons(port);   
      //inet_addr函式將用點分十進位制字串表示的IPv4地址轉化為用網路   
      //位元組序整數表示的IPv4地址   
      addr.sin_addr.s_addr = inet_addr(ip);   
  
      //不需要監聽  
  
      //發起連線  
//    struct sockaddr_in peer;  
      socklen_t addr_len = sizeof(addr);  
      int connect_fd = connect(clt_sock, (struct sockaddr*)&addr, addr_len);  
      if(connect_fd < 0)  
      {  
          perror("connect");  
          return 2;  
      }  
      char buf[1024];  
  
      while(1)  
      {  
          memset(buf, '\0', sizeof(buf));  
          printf("client please enter: ");  
          fflush(stdout);  
          ssize_t size = read(0, buf, sizeof(buf) - 1);  
          if(size > 0)  
          {  
              buf[size - 1] = '\0';  
          }  
          else if(size == 0)  
          {  
              printf("read is done...\n");  
              break;  
          }  
          else  
          {  
              perror("read");  
              return 4;  
          }  
          write(clt_sock, buf, strlen(buf));  
       }  
      close(clt_sock);  
      return 0;  
}  
//

三、一個服務端和多個客戶端

1、server端

//
#include <sys/types.h>  
#include <sys/socket.h>  
#include <stdio.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <unistd.h>  
#include <string.h>  
#include <stdlib.h>  
#include <fcntl.h>  
#include <sys/shm.h> 
#include <wiringPi.h>
#include <wiringSerial.h> 
  
#define PORT  7654  
#define QUEUE_SIZE   10  
#define BUFFER_SIZE 1024  
  
//傳進來的sockfd,就是互相建立好連線之後的socket檔案描述符  
//通過這個sockfd,可以完成 [服務端]<--->[客戶端] 互相收發資料  
void str_echo(int sockfd)  
{  
    char buffer[BUFFER_SIZE];  
    pid_t pid = getpid();  
    while(1)  
    {  
        memset(buffer,0,sizeof(buffer));  
        int len = recv(sockfd, buffer, sizeof(buffer),0);
        if(strcmp(buffer,"exit\n")==0)  
        {  
            printf("child process: %d exited.\n",pid);  
            break;  
        }
        
        if (len > 0)
        {
            printf("client#: %s\n", buffer);
            if (len = 1 && buffer[0] == '1')
            {
                digitalWrite(0, HIGH);
            } else {
                digitalWrite(0, LOW);
            }
        } else if (len == 0) {
            digitalWrite(0, LOW);
            printf("read is done...\n");
        } else {
            digitalWrite(0, LOW);
            perror("read");
        }

          
        printf("pid:%d receive:\n",pid);  
        //fputs(buffer, stdout);  
        send(sockfd, buffer, len, 0);  
    }  
    close(sockfd);  
}  
  
int main(int argc, char **argv)  
{  
    //GPIO
    wiringPiSetup();
    pinMode(0, OUTPUT);

    //定義IPV4的TCP連線的套接字描述符  
    int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);  
  
    //定義sockaddr_in  
    struct sockaddr_in server_sockaddr;  
    server_sockaddr.sin_family = AF_INET;  
    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
    server_sockaddr.sin_port = htons(PORT);  
  
    //bind成功返回0,出錯返回-1  
    if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)  
    {  
        perror("bind");  
        exit(1);//1為異常退出  
    }  
    printf("bind success.\n");  
  
    //listen成功返回0,出錯返回-1,允許同時幀聽的連線數為QUEUE_SIZE  
    if(listen(server_sockfd,QUEUE_SIZE) == -1)  
    {  
        perror("listen");  
        exit(1);  
    }  
    printf("listen success.\n");  
  
    for(;;)  
    {  
        struct sockaddr_in client_addr;  
        socklen_t length = sizeof(client_addr);  
        //程序阻塞在accept上,成功返回非負描述字,出錯返回-1  
        int conn = accept(server_sockfd, (struct sockaddr*)&client_addr,&length);  
        if(conn<0)  
        {  
            perror("connect");  
            exit(1);  
        }  
        printf("new client accepted.\n");  
  
        pid_t childid;  
        if(childid=fork()==0)//子程序  
        {  
            printf("child process: %d created.\n", getpid());  
            close(server_sockfd);//在子程序中關閉監聽  
            str_echo(conn);//處理監聽的連線  
            exit(0);  
        }  
    }  
  
    printf("closed.\n");  
    close(server_sockfd);  
    return 0;  
}  
//

2、client端

//
/************************************************************************* 
    > File Name: client.c 
    > Author: Sen  
    > Date: 2018-5-8 
 ************************************************************************/  
  
#include <stdio.h>  
#include <string.h>  
#include <stdlib.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <sys/un.h>  
#include <arpa/inet.h>  
#include <netinet/in.h>  
  
const int port = 7654;  
const char* ip = "192.168.1.32";   
  
int main()  
{  
      //建立套接字,即建立socket   
      int clt_sock = socket(AF_INET, SOCK_STREAM, 0);   
      if(clt_sock < 0)  
      {  
          //建立失敗  
          perror("socket");  
          return 1;  
      }  
  
      //繫結資訊,即命名socket   
      struct sockaddr_in addr;   
      addr.sin_family = AF_INET;   
      addr.sin_port = htons(port);   
      //inet_addr函式將用點分十進位制字串表示的IPv4地址轉化為用網路   
      //位元組序整數表示的IPv4地址   
      addr.sin_addr.s_addr = inet_addr(ip);   
  
      //不需要監聽  
  
      //發起連線  
//    struct sockaddr_in peer;  
      socklen_t addr_len = sizeof(addr);  
      int connect_fd = connect(clt_sock, (struct sockaddr*)&addr, addr_len);  
      if(connect_fd < 0)  
      {  
          perror("connect");  
          return 2;  
      }  
      char buf[1024];  
  
      while(1)  
      {  
          memset(buf, '\0', sizeof(buf));  
          printf("client please enter: ");  
          fflush(stdout);  
          ssize_t size = read(0, buf, sizeof(buf) - 1);  
          if(size > 0)  
          {  
              buf[size - 1] = '\0';  
          }  
          else if(size == 0)  
          {  
              printf("read is done...\n");  
              break;  
          }  
          else  
          {  
              perror("read");  
              return 4;  
          }  
          write(clt_sock, buf, strlen(buf));  
       }  
      close(clt_sock);  
      return 0;  
}  
//