25、新手入手樹莓派教程--通過TCP遠端控制GPIO(C++)
阿新 • • 發佈:2019-01-08
一、分析
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;
}
//