CHÚ Ý : Từ 2019 MLAB có thêm một website cho riêng Raspberry Pi và trở thành website chính về Raspberry Pi tại MLAB, các thông tin về sản phẩm - tin tức cập nhật về Raspberry Pi - Bài viết kỹ thuật hỗ trợ cho Raspberry Pi, ... MLAB cập nhật tại website : pivietnam.com.vn MLAB trân trọng thông báo tới quý khách hàng!!! Các bạn có thể tham khảo các bài viết hỗ trợ kỹ thuật và các tin tức mới nhất tại phần "tin tức"trên website PVIETNAM.COM.VN Bài viết hỗ trợ kỹ thuật tại website PIVIETNAM.COM.VN - Bài 6: Lập trình giao tiếp mạng TCP/IP Raspberry Pi Phần 2 (Link here) Trong phần 1 mình đã trình bày các lý thuyết để xây dựng được mô hình server- client đơn giản với giao thức truyền nhận thông tin là TCP-IP. Các bạn đã có thể dùng Raspberry làm server trung tâm. Máy tính (client) có thể thông gửi và nhận dữ liệu tới Pi mà qua đó có thể gián tiếp điều khiển hoặc xem xét thông tin của các client khác.
Tuy nhiên phần trước server mới chỉ có thể kết nối với duy nhất một client. Các client khác muốn kết nối tới đều phải chờ đợi client đang kết nối kết thúc. Phần tiếp theo đây sẽ trình bày cách giải quyết để server thực sự là server – có thể cùng lúc làm việc với nhiều client. Chuẩn bị phần cứng : Nền tảng UNIX hỗ trợ nhiều phương thức xử lý khác nhau và chia làm 2 nhánh:
Mỗi phương thức có nhiều ưu điểm, nhược điểm khác nhau. Trong bài này mình sẽ trình bày phương thức thread-base. Lý do vì nó đơn giản để thực hiện và có thể thỏa mãn nhu cầu về số lượng client lớn. 1. MultithreadTrong linux multithread được hỗ trợ bởi thư viện Pthread được nhúng sẵn trong linux. Các bạn không cần phải quan tâm gì thêm mà chỉ cần uống nhanh một tách trà, bật Raspberry lên và bắt tay vào ngay vào code :) Công việc luôn được bắt đầu bằng việc khai báo thư viện
#include <pthread.h>
Hàm thiết lập và hủy bỏ thread : int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); void pthread_exit(void *retval); Trong đó :
Hãy cùng xem ví dụ dưới đây, các bạn nên copy code vào để chạy thử trước : // thread.c #include <stdio.h> #include <unistd.h> // for sleep #include <pthread.h> // Ham xu ly cho thread 1 void *Thread1(void *threadid){ while(1){ printf("thread 1 : hello\n"); sleep(3); } } // Ham xu ly cho thread 2 void *Thread2(void *threadid){ while(1){ printf("thread 2 : hello\n"); sleep(4); } } int main () { pthread_t threads[NUM_THREADS]; int rc, i = 0; // Tao thread 1 printf("Creating thead %d, \n",i); if ( (rc = pthread_create(&threads[i], NULL, Thread1, NULL)) ){ printf("Error:unable to create thread, %d\n",rc ); return 0; } i++; // Tao thread 2 printf("Creating thead %d, \n",i); if ( (rc = pthread_create(&threads[i], NULL, Thread2, NULL)) ){ printf("Error:unable to create thread, %d\n",rc ); return 0; } // Ham main van se chay nhiem vu rieng cua no while(1){ printf("main thread : hello\n"); sleep(2); } pthread_exit(NULL); return 0; } Các bạn có thể down code trực tiếp từ github của mình. Biên dich chương trình với lệnh gcc -o thread thread.c –lpthread # -lpthread khai báo dùng thư viện pthread Kết quả sẽ hiển thị như sau
Chương trình sẽ chạy trêm 3 luồng riêng biệt là main thread, thread1 và thread2. Mỗi thread sẽ gọi hàm xử lý riêng và sẽ hiển thị câu chào lên màn hinh. Tất nhiên là các thread có thể gọi chung một hàm xử lý. Lưu ý rằng hàm xử lý luôn làm hàm con trỏ dạng void. Với úng dụng của thread chương trình có thẻ hoạt động đa nhiệm không chỉ với server-client mà với bất cứ chương trình nào bạn mong muốn thực hiện đa nhiệm.2. Server – multitaskingTừ ví dụ của phần trước là client trên máy tính kết nối tới Pi. Bây giờ mình sẽ tận dụng luôn từ ví dụ đó để có thể test với server mới. Server mới có thể cùng một lúc nhận nhiều tin nhắn của client và hiển thị lên màn hình, server mới cũng sẽ biết chính xác là client nào gửi thông tin cho mình . Các bạn có thể sửa từ bản server.c cũ như sau : // cau truc struct cho thread, them vao phan dau trong server.c struct ThreadArgs{ int clntSock; /* Socket descriptor for client */ }; // Ham xu ly client, them vao phan dau trong server.c void *HandleClient(void *threadArgs){ int clntSock; int recvMsgSize; char buffer[BUFFSIZE]; bzero(buffer,BUFFSIZE); clntSock = ((struct ThreadArgs *) threadArgs) -> clntSock; while(1){ recvMsgSize = recv(clntSock,buffer,BUFFSIZE,0); if (recvMsgSize < 0) error("ERROR reading from socket"); else if(recvMsgSize>0){ printf(". Client[%d]: %s\n",clntSock,buffer); bzero(buffer,strlen(buffer)); } else{ printf("- Client[%d]: disconnected !\n",clntSock); break; } } close(clntSock); } // Thay the tu doan accept den het ham while(1) trong server.c, nhiem vu cua phan nay la tao thread khi co thread moi while(1){ // Wait for a client to connect if( (clntSock = accept(servSock, (struct sockaddr*) &cli_addr, &clntLen)) < 0) error("accept() failed !"); getpeername(clntSock, (struct sockaddr *) &cli_addr, &clntLen); /* Create separate memory for client argument */ if ((threadArgs = (struct ThreadArgs *) malloc(sizeof(struct ThreadArgs))) == NULL) error("malloc() failed"); threadArgs -> clntSock = clntSock; if (pthread_create(&threadID, NULL, HandleClient, (void *) threadArgs) != 0) error("pthread_create() failed"); printf("\n+ New client[%d][Addr:%s][Port:%d]\n\n", clntSock, inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port)); } Các bạn hãy xem kỹ code trên github nhé. Giải thích thêm :
Biên dich chương trình với lệnh gcc -o server-thread server-thread.c -lpthread Bây giờ các bạn hãy chạy thử ./server-thread, và bật nhiều client cùng một lúc trên nhiều terminal khác nhau để kết tới server. 3. Chương trình client với Esp8266Mình sẽ lấy esp8266 làm client. Các bạn xem thêm phần cài đặt thư viện và lập trình cho esp8266 trên arduino tại đây. Chương trình cho esp8266 cũng sẽ thực hiện công việc giống hệt client trên máy tính. Nó sẽ gửi tin nhắn đến cho server. Chương trình như sau : // WifiClientBasic.ino #include <ESP8266WiFi.h> #include <ESP8266WiFiMulti.h> ESP8266WiFiMulti WiFiMulti; const uint16_t port = 8888; // port tương ứng với server const char * host = "192.168.1.23"; // ip của raspberry void setup() { Serial.begin(115200); delay(10); // Can thay ten wifi và mat khau nha ban vao WiFiMulti.addAP("ten wifi", "mat khau la"); Serial.println(); Serial.println(); Serial.print("Wait for WiFi... "); while(WiFiMulti.run() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); delay(500); } void loop() { Serial.print("connecting to "); Serial.println(host); // Use WiFiClient class to create TCP connections WiFiClient client; if (!client.connect(host, port)) { Serial.println("connection failed"); Serial.println("wait 5 sec..."); delay(5000); return; } while(1){ if (Serial.available() > 0) { String str = Serial.readString(); // gui cho server client.print(str); Serial.print("message: "); Serial.println(str); } } //read back one line from server //String line = client.readStringUntil('\r'); //client.println(line); //Serial.println("closing connection"); client.stop(); } Các bạn phải chú ý tới những thiết lập :
Kết quả
|