RPi--lab8網絡矩陣顯示

Lab8 : 網絡LED矩陣顯示器 - 嵌入式與計算機網絡

前言

本次實驗延續上次實驗的環境,使用MAX7219驅動8x8點陣。上位機使用Ubuntu 14.04,下位機使用Raspberry pi 2。

使用的還是上次實驗編譯好的非阻塞式寫入點陣支持內核模塊。

控制點陣顯示字符
通過write函數向device寫入數據即可。
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int Matrix;

#define ALLCHAR "0123456789abcdefghijklmnopqrstuvwxyz"

int main(){
    Matrix = open("/dev/matrix", O_WRONLY);
    if (Matrix < 0){
        fprintf(stderr, "Cound not open matrix device");
        exit(1);
    }
    write(Matrix, ALLCHAR, strlen(ALLCHAR));
    return 0;
}
編寫網絡程序接受TCP請求
使用linux下的socket編程,接受外部TCP請求,並將其發送來的所有數據寫入matrix設備即可實現顯示功能。


Socket流程圖 | 圖自Linux的SOCKET編程詳解:

這裏寫圖片描述

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int Matrix;
int server;

#define PORT 8080
#define ADDR "0.0.0.0"
#define QUEUE 20

#define BUFF_SIZE 2048 main(){
    // 打開matrix
    Matrix = open("/dev/matrix", O_WRONLY);
    if (Matrix < 0){
        fprintf(stderr, "Cound not open matrix device\n");
        exit(1);
    }
    // 建立服務器
    int server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = inet_addr(ADDR);
    serverAddr.sin_port = htons(PORT);

    // 綁定ip以及端口
    if (bind(server, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1){
        fprintf(stderr, "Count not bind %s:%d\n", ADDR, PORT);
        exit(1);
    }

    if (listen(server, QUEUE) == -1){
        fprintf(stderr, "Listen error\n");
        exit(1);
    }

    printf("Server running at %s:%d\n", ADDR, PORT);

    while (1){
        struct sockaddr_in clientAddr;
        socklen_t length = sizeof(clientAddr);

        // 對連入的連接進行處理
        int conn = accept(server, (struct sockaddr*)&clientAddr, &length);
        if (conn < 0){
            fprintf(stderr, "Connect error");
            exit(1);
        }

        printf("A new connection from %s:%d\n", inet_ntoa(clientAddr.sin_addr), clientAddr.sin_port);

        // 處理連接發送過來的字符
        while (1){
            char receiveBuf[BUFF_SIZE];
            int count;
            memset(receiveBuf, 0, sizeof(receiveBuf));

            // 接收字符
            count = recv(conn, receiveBuf, sizeof(receiveBuf), 0);

            // 如果接收到的字符爲空,則表示離開
            if (count == 0){
                close(conn);
                break;
            }

            // 將接收到的所有字符發送給matrix進行顯示
            write(Matrix, receiveBuf, count);
        }
    }
    close(server);
    return 0;
}
樹莓派本地連入:

這裏寫圖片描述

上位機遠程連入:

這裏寫圖片描述

使用線程處理多個連接
上一節的程序使用的是阻塞式的處理連接,這將導致服務器每次accept了一個連接之後,無法再處理其餘連接。

而這種情況的處理方式有很多。可以使用一個線程對應一個socket fd的方式進行阻塞式監聽。也可以使用IO多路複用,如select、poll、epoll,在單線程的環境下進行高效的網絡IO操作。

使用線程的方式對於阻塞式程序的改動較小,基本上邏輯還是一致的。
…………
void* serverRecv(void* data){
    int conn = *(int*)data;

    while (1){
        char receiveBuf[BUFF_SIZE];
        int count;
        memset(receiveBuf, 0, sizeof(receiveBuf));

        count = recv(conn, receiveBuf, sizeof(receiveBuf), 0);

        if (count == 0){
            close(conn);
            break;
        }

        write(Matrix, receiveBuf, count);
    }

    pthread_exit(NULL);
    return NULL;
}
…………
int main(){
…………
    printf("Server running at %s:%d\n", ADDR, PORT);

    while (1){
        pthread_t thread;
        struct sockaddr_in clientAddr;
        socklen_t length = sizeof(clientAddr);
        int conn = accept(server, (struct sockaddr*)&clientAddr, &length);
        int result;
        if (conn < 0){
            fprintf(stderr, "Connect error");
            exit(1);
        }

        printf("A new connection from %s:%d\n", inet_ntoa(clientAddr.sin_addr), clientAddr.sin_port);

        result = pthread_create(&thread, NULL, serverRecv, &conn);
        if (result < 0){
            printf("Create thread error\n");
            exit(1);
        }
    }
…………
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章