基于ARM-Linux嵌入式系統(tǒng)的多進程并發(fā)服務器設計
摘要:隨著物聯(lián)網(wǎng)、智能電網(wǎng)、智能移動設備的發(fā)展,我們將能在任何時候任何地方獲取我們所需的信息,本文設計一款基于ARM-Linux嵌入式系統(tǒng)的多進程并發(fā)服務器。它擁有傳統(tǒng)服務器的功能,可遠程訪問和操作,同時又具有體積小、噪聲低、低功耗、低成本的優(yōu)勢,非常適合用于智能樓宇的家用服務器。
本文引用地址:http://m.butianyuan.cn/article/201609/304671.htm目前大家所用的大多是X86服務器,其功能完善、運行速度快、軟件支持性好等優(yōu)點,已被人們普遍認同。但其由于價格昂貴、功耗高、噪聲大等原因,一般只應用于工廠、企事業(yè)單位,但隨著互連網(wǎng)的發(fā)展,我們需要更多的小型服務器終端,因此,低成本、低功耗的嵌入式服務器將有極大的應用空間。
面向連接的并發(fā)服務器是目前Linux網(wǎng)絡服務器的主流形式。它采用主、從服務器的工作方式,能較好地解決了網(wǎng)絡中客戶進程的并發(fā)請求問題。目前在嵌入式領域,基于ARM技術的微處理器應用約占據(jù)了32位RISC微處理器80%以上的市場份額,同時,ARM處理器和嵌入式Linux的結(jié)合也正變得越來越緊密,在工業(yè)控制、消費類電子產(chǎn)品、通信系統(tǒng)、無線系統(tǒng)等各類產(chǎn)品市場都可以看到ARM與Linux相結(jié)合的身影。因此,本文介紹了一種基于ARM-Linux嵌入式系統(tǒng)的多進程并發(fā)服務器設計。
1 并發(fā)服務器原理及框架
1. 1 基本的C/S服務模型
相互通信的網(wǎng)絡程序通??梢苑譃榭蛻舳撕头掌鞫藘刹糠帧:唵蔚腃/S服務模式客戶端和服務器采用的是一對一的關系,而實際上一個客戶同時可以與多個服務器通信,一個服務器同時也能與多個客戶通信。
Linux下使用TCP套接字編程可以實現(xiàn)基于TCP/IP協(xié)議的面向連接的通信,它分為服務器端和客戶端兩部分,如圖1所示。
服務器端與客戶端連接的步驟如下:
1)使用socket0函數(shù)創(chuàng)建套接字;
2)將創(chuàng)那的套接字綁定到指定的地址結(jié)構
3)Listen0函數(shù)設置套接字為監(jiān)聽模式,使服務器進入被動打開的狀態(tài)
4)接受客戶端的連接請求,建立連接
5)終止連接
客戶端實現(xiàn)步驟:
1)使用socket0函數(shù)創(chuàng)建套接字
2)調(diào)用connect0函數(shù)建立一個TCP服務器的連接
3)發(fā)送數(shù)據(jù)請求,接收服務器的數(shù)據(jù)應答
4)終止連接
這樣就建立了最簡單的C/S連接模式,而所有基于TCP套接字的網(wǎng)絡服務也都是建立在這個基礎上的。
1.2 多進程并發(fā)服務器模型
前面介紹了簡單的TCP客戶端/服務器概念和連接,其中服務器每次只能處理一個客戶的請求,它的實現(xiàn)雖然很簡單但效率卻很低,在實際應用中,這樣的服務器是不能滿足實際需求的。
在實際應用中為了讓一個服務器同時為多個客戶服務,處理多個客戶的請求,那么就需要用并發(fā)服務器。Linux下主要支持的并發(fā)服務器有進程、線程。創(chuàng)建線程要比進程快,但一個進程內(nèi)的所有線程共享相同的內(nèi)存空間、全局變量等信息,所以當一個線程崩潰時,它會影響同一進程中的其他線程。
Linux系統(tǒng)中可以同時存在多個進程,但相對線程來說,進程是獨立的。它擁有獨立的地址空間、執(zhí)行堆棧、文件描述符等,在未經(jīng)允許的情況下,一個進程不能訪問另一個進程的資源,因此一個進程崩潰不會造成其他進程的崩潰。由于考慮遠程監(jiān)控系統(tǒng)要求的安全性和穩(wěn)定性,本系統(tǒng)設計為多進程并發(fā)服務器。圖2為并發(fā)服務器的基本模型圖。
1.3 多進程服務器原理
在多進程并發(fā)服務器中是通過調(diào)用fork或vfork函數(shù)來創(chuàng)建新進程。當父進程產(chǎn)生新的子進程后,父、子進程共享父進程在調(diào)用fork之前的所有描述符。接下來父進程只負責接收客戶請求,而子進程只負責處理客戶請求。
圖3說明父進程調(diào)用fork生成子進程后,父、子進程對客戶請求和描述符的操作過程。
1)當服務器調(diào)用accept0函數(shù)時,連接請求從客戶到達服務器時雙方狀態(tài)。
2)當客戶的請求被接受后。接下來服務器就會調(diào)用fork函數(shù)生成子進程。
3)最后父進程關閉已連接描述符,由子進程關閉監(jiān)聽描述符,這樣既可以節(jié)省系統(tǒng)資源,又可以防止父、子進程同時對共享描述符進程操作。至此子進程處理與客戶的連接,父進程可以對監(jiān)聽描述符再次調(diào)用accept,繼續(xù)處理下一個客戶的請求。
2 功能代碼分析
網(wǎng)絡主程序設計其實主要也就是父進程所執(zhí)行的程序,程序設計的流程圖如4所示。
linux中的網(wǎng)絡編程通過socket接口實現(xiàn)。socket既是一種特殊的I/O,它也是一種文件描述符。一個完整的socket包括協(xié)議、本地地址、本地端口、遠程地址、遠程端口;每一個socket有一個本地的唯一socket號,由操作系統(tǒng)自動分配。以下是建立TCP socket,其中AF_INET為IPv4,SOCK_STREAM為TCP協(xié)議,如建立失敗則返回-1。
listen_fd=socket(AF_INET,SOCK_STREAM,0)
調(diào)用bzero初始化套接字地址結(jié)構,并對地址結(jié)構中的成員賦值,代碼如下。
bzero(client_addr,sizeof(struct sockaddr_in));
client_addr.sin_family=AF_INET;
client_addr.sin_port=htons(MY_PORT);
client_addr.sin_addr.s_addr=htonl(INADDR_ANY);
為了給調(diào)用socket0函數(shù)產(chǎn)生的套接字分配一個本地協(xié)議地址,建立地址與套接字的對應關系,就要用到綁定函數(shù)bind0。通過綁定后端口號保證了地址信息的唯一性。如失敗返回-1。
評論