l 引言
Linux具有豐富的網(wǎng)絡功能,完善的內置網(wǎng)絡是Linux的一大特點。嵌入式Linux專用于微控制器,同樣具有優(yōu)秀的網(wǎng)絡功能。Linux是一種可移植的操作系統(tǒng),能夠在從微型計算機到大型計算機的任何環(huán)境中和任何平臺上運行。可移植性為運行Linux的不同計算機平臺與其他任何機器進行準確而有效的通訊提供了手段,不需要另外增加特殊的,昂貴的通訊接口。
該文在構建基于嵌入式Linux和MPC852T無線網(wǎng)關平臺的基礎上,編程實現(xiàn)了無線網(wǎng)關平臺與無線終端之間的無線通信,并給出了無線網(wǎng)關平臺與無線終端之間通信的測試結果。
2 Linux下的socket編程
2.1 Socket編程
socket有3種類型:流式套接字、數(shù)據(jù)報套接字及原始套接字。流式套接字定義了一種可靠的面向連接的服務,實現(xiàn)了無差錯的數(shù)據(jù)傳輸。數(shù)據(jù)報套接字定義了一種無連接的服務,數(shù)據(jù)通過相互獨立的報文進行傳輸,是無序的,并且不保證可靠。原始套接字允許對低層協(xié)議如IP或ICMP直接訪問,主要用于新的網(wǎng)絡協(xié)議實現(xiàn)的測試等。
無連接服務器一般都是面向事務處理的,一個請求和一個應答就完成客戶程序與服務程序之間的相互作用。
面向連接服務器處理的請求比較復雜,往往是并發(fā)服務器。工作過程如下:服務進程首先調用socket( )創(chuàng)建一個字節(jié)流套接字,并調用bind( )將服務器地址捆扎在該套接字上,接著調用listen( )監(jiān)聽連接請求,隨后調用accept( )做好與客戶進程建立連接的準備,無連接請求時,服務進程被阻塞。當連接請求到來后,服務器進程被喚醒,建立一個新的Socket,并用新套接字同客戶進程的套接字建立連接,而服務進程最早生成的套接字則繼續(xù)用于監(jiān)聽網(wǎng)絡上的服務請求。客戶進程調用socket( )創(chuàng)建字節(jié)流套接字,然后調用connect( )向服務進程發(fā)出連接請求。服務進程和客戶進程通過調用read( )/recv( )和Write( )/send( )交換數(shù)據(jù)。
2.2 Linux下的socket函數(shù)庫
socket是面向用戶的,針對客戶和服務器程序提供不同的socket系統(tǒng)調用。客戶隨機申請一個socket,系統(tǒng)為之分配一個socket號,服務器擁有全局公認的socket,任何客戶都可以向它發(fā)出一個連接請求和信息請求。無論socket的內部機制如何,它提供給程序員的最終是一組系統(tǒng)調用,即socket的庫函數(shù)。Linux這些庫函數(shù)同樣適用于嵌入式linux。下面是編制程序常用的庫函數(shù):
1) socket( ):建立Socket,此函數(shù)用來建立Socket描述字,并為此Socket建立資源(為一個Socket數(shù)據(jù)結構分配存儲空間)。應用程序在使用socket之前,首先必須擁有一個socket。socket( )向應用程序提供創(chuàng)建socket的手段。socket( )函數(shù)原形為int socket(int domain,int type,int protoco1);函數(shù)中的domain是參數(shù)指定通信中使用的協(xié)議簇,也就是網(wǎng)絡的類型,通常為PF_INET,表示互聯(lián)網(wǎng)協(xié)議族(TCP/IP協(xié)議族);type參數(shù)指定socket的類型:SOCK_STREAM或SOCK_DGRAM,Socket接口還定義了原始Socket(SOCK_RAW),允許程序使用低層協(xié)議;protocol是參數(shù)指定通信中使用的協(xié)議。
函數(shù)在正常時返回socket描述符;否則返回l,錯誤狀態(tài)在全局變量error里。
2) bind( ):綁定本地地址,即將一個本地地址與一個SOCKET描述字連接在一起。此函數(shù)在服務程序上使用,是調用監(jiān)聽函數(shù)listen()必須要調用的函數(shù)。
Bind函數(shù)原型為:
int bind(int sockfd, struct sockaddr *my_addr, int addrlen)。bind()函數(shù)給已經打開的socket指定本地地址。函數(shù)中的sockfd是調用socket函數(shù)返回的socket描述符;addrlen是my-addr結構的長度,常被設置為sizeof(struct sockaddr);my-addr是用于偵聽連接請求的本地地址。
函數(shù)在正常時返回0,否則返回l,同時error是系統(tǒng)錯誤碼。
3) listen( ):準備接收連接請求。在用bind()給一個socket設定本地地址之后,就可以將這個socket用于接受連接請求,即listen()。函數(shù)原形為int listen(int s,int backlog);函數(shù)中的s是socket描述符;backlong是連接請求暫存隊列長度。
函數(shù)正常時返回0,否則返回1,同時error是系統(tǒng)錯誤碼。
4) accept( ):服務端應用程序調用此函數(shù)來接受客戶端socket連接請求。在系統(tǒng)調用listen( )之后,系統(tǒng)就在socket的連接請求暫存隊列里存放每一個向該socket建立的連接請求,accept()的作用是從該暫存隊列中取出一個連接請求,用該socket的數(shù)據(jù),創(chuàng)建一個新的socket用來在服務端和客戶端之間傳遞接收信息,而原來socket仍然可以接收其他客戶端的連接要求。
函數(shù)正常創(chuàng)建了一個新的連接,那么返回非負的整數(shù),即新連接的socket描述符,否則返回l,error是系統(tǒng)錯誤碼。
5) connect( ):建立連接。bind( ),listen( )和accept( )都是用于被動地等待對方建立連接時需要使用的,connect( )函數(shù)是在主動地向對方建立連接時使用的。函數(shù)原形為int connect(int sockfd,struct sockaddr*srvaddr,int addrlen);函數(shù)中的sockfd是socket描述符;srvaddr是通信目的方地址;addrlen是目的地址長度。
函數(shù)在正常建立連接時返回0,否則返回l,系統(tǒng)錯誤碼在error中。
6) close( ):此函數(shù)是用來關閉某一socket。socket和文件描述符的關閉操作都使用這個函數(shù)。函數(shù)原形為int close(int fd);參數(shù)fd是socket描述符。函數(shù)在正常時返回0,返回1表示出錯。
7) send( )/recv( ):用于socket的發(fā)送和接收數(shù)據(jù)。在連接建立完成后,通信雙方就可以使用以上這些函數(shù)來進行數(shù)據(jù)的發(fā)送和接收操作。
3 無線網(wǎng)關平臺的構建
為了將無線終端設備接入控制網(wǎng)絡實現(xiàn)遠程監(jiān)控,根據(jù)條件構建了基于MPC852T和嵌入式Linux的無線網(wǎng)關平臺。MPC852T是Motorola推出的面向低端的一款通信處理器,具有通信和網(wǎng)絡處理能力強、可靠性高、功耗低、功能集成度高等優(yōu)點,并且有眾多的操作系統(tǒng)支持,這使得它在各種嵌入式系統(tǒng),尤其是在網(wǎng)絡通信以及數(shù)據(jù)采集和傳輸?shù)认到y(tǒng)中的應用較為廣泛。
無線網(wǎng)關的硬件設計方案采用中心控制方案,中央處理器選用MPC852T,在MPC852T外圍配置一個RS-232串口、一個10M以太網(wǎng)口、一個100M以太網(wǎng)接口、SDRAM同步動態(tài)隨機存儲器等構成無線網(wǎng)關的硬件平臺,無線網(wǎng)關的硬件系統(tǒng)結構圖如圖1所示。
4 無線網(wǎng)關與無線終端通信的實現(xiàn)
嵌入式Linux具有完善的TCP/IP協(xié)議棧,為滿足工業(yè)控制過程中傳輸數(shù)據(jù)量小、可靠性高、速度快等要求,這里使用socket編程來實現(xiàn)網(wǎng)絡通信。無線終端通過無線網(wǎng)卡與無線網(wǎng)關自動建立鏈接,無線終端完成數(shù)據(jù)的采集,并將采集的數(shù)據(jù)以無線的方式發(fā)送給網(wǎng)關,無線網(wǎng)關把收到的數(shù)據(jù)上傳給上位機進行分析、處理,最后計算出數(shù)據(jù)發(fā)送的速率。
將編寫好的服務器端和終端程序進行交叉編譯,將編譯得到的二進制可執(zhí)行文件添加到RAMDISK中,壓縮新生成的ramdisk.image文件系統(tǒng)映像文件,重新編譯Linux內核,生成Linux內核映像文件,然后將內核映像文件燒寫到無線網(wǎng)關平臺的FLASH中。無線網(wǎng)關平臺(服務器端)的主程序代碼如下:
#define PORT 3000 /*設定服務器監(jiān)聽端口*/
………………
int main(int argc,char* argv[ ])
{
int second;
int sockfd,new_fd; /* sockfd為監(jiān)聽用描述符*/
struct sockaddr_in srvaddr; /*定義服務器sock地址*/
struct sockaddr_in cliaddr; /*定義客戶的sock地址*/
………………
if(bind(sockfd,(struct sockaddr *)&srvaddr,sizeof(struct sockaddr))==-1) /*綁定*/
………………
if(listen(sockfd, QUEUE_SIZE) == -1) /*監(jiān)聽端口是否有請求*/
………………
for(;;){ /*開始服務器循環(huán)*/
/*等待連接*/
sin_size=sizeof(struct sockaddr_in);
new_fd=accept(sockfd,(struct sockaddr*) &cliaddr,&sin_size); /*接收連接請求*/
printf("Server:Got connection from %s \n",
inet_ntoa(cliaddr.sin_addr));
if(read(new_fd,&second,4)==-1) /*接收連接請求*/
………………
close(new_fd); /*父進程不再需要該socket*/
………………;
close(sockfd);
return 0;
}
}
5 測試結果
在上位機開啟通信終端,設置好串口參數(shù),進入超級終端。無線網(wǎng)關平臺上運行服務器端程序,同時在終端上運行客戶端程序,即可進行測試,測試結果如圖2所示。
圖2 無線網(wǎng)關與無線終端測試結果圖
6 結 語
目前基于TCP/IP協(xié)議的工業(yè)以太網(wǎng)的在組網(wǎng)時仍需要布線,但在工業(yè)現(xiàn)場,布線時常會受到限制,電纜的連接也限制了現(xiàn)場設備的移動和網(wǎng)絡結構的重組,還有一些高速旋轉設備根本無法通過電纜來傳輸數(shù)據(jù)。將802.11b無線通信技術應用于工業(yè)控制網(wǎng)絡,工控網(wǎng)絡就兼有了無線通信的優(yōu)點:現(xiàn)場設備無需電纜即可與控制網(wǎng)絡連接,實現(xiàn)現(xiàn)場數(shù)據(jù)的無線采集和傳輸,對于在一些不可預知的環(huán)境,尤其是不適于布線的強腐蝕惡劣環(huán)境。本文作者創(chuàng)新點:通過Linux下的socket編程實現(xiàn)了無線網(wǎng)關與無線終端的通信,可以使用無線通信來完成對現(xiàn)場設備的控制。