李淑梅,王志彬
(吉林師范大學(xué) 計(jì)算機(jī)學(xué)院,吉林 四平 136000)
Linux操作系統(tǒng)堅(jiān)持以網(wǎng)絡(luò)為核心為其設(shè)計(jì)思想,使其具有突出的網(wǎng)絡(luò)性能,同時(shí)Linux具有多用戶、多線程的能力,都為開發(fā)高性能的網(wǎng)絡(luò)通信軟件奠定了良好的基礎(chǔ)[1-2].
在Linux操作系統(tǒng)中,實(shí)現(xiàn)網(wǎng)絡(luò)通信主要采用的技術(shù)就是套接字socket(又稱BSD socket).socket作為開放的網(wǎng)絡(luò)編程接口,以其眾多的優(yōu)勢(shì)廣泛地應(yīng)用在網(wǎng)絡(luò)編程中.目前,大部分的局域網(wǎng)聊天系統(tǒng)都要求多用戶同時(shí)在線,還要資源開銷少、響應(yīng)速度快的短信式交互,并且對(duì)數(shù)據(jù)可靠性要求不高,所以基于UDP 的socket成為開發(fā)網(wǎng)絡(luò)通信軟件的首選工具[3-4].
在網(wǎng)絡(luò)中,如果兩臺(tái)主機(jī)是通過“通道”進(jìn)行通信,那么socket接口就是“通道”兩端的出入口.socket接口為主機(jī)提供了一個(gè)通信端口,通過“通道”,可以與另一端具有socket接口的主機(jī)通信.如圖1所示,網(wǎng)絡(luò)上傳輸?shù)男畔?,最終都是通過socket接口收發(fā)的.
socket的類型有SOCK_STREAM、SOCK_DGRAM和SOCK_RAW三種,用戶使用的主要是前兩種類型.SOCK_STREAM采用TCP協(xié)議,提供面向連接的、可靠的數(shù)據(jù)傳輸服務(wù);SOCK_DGRAM采用UDP協(xié)議,提供無連接的、不可靠的數(shù)據(jù)傳輸服務(wù).
圖1 socket的地位
作為開放系統(tǒng)互聯(lián)參考模型傳輸層上兩個(gè)主要協(xié)議之一的UDP,為應(yīng)用程序提供無連接服務(wù).基于UDP的無連接服務(wù),不必事先與對(duì)方建立連接,客戶程序與服務(wù)程序之間的相互作用只需一個(gè)請(qǐng)求和一個(gè)應(yīng)答就完成,因而數(shù)據(jù)傳輸?shù)难舆t極??;不需要維護(hù)發(fā)送雙方的狀態(tài),可以同時(shí)支持更多的在線客戶,使用更靈活;由于數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)單,UDP數(shù)據(jù)包的標(biāo)題很短(只有8個(gè)字節(jié)),對(duì)資源的需求更少;由于沒有擁塞控制的限制,吞吐量只受應(yīng)用程序產(chǎn)生數(shù)據(jù)的速率、發(fā)送端主機(jī)的性能以及傳輸帶寬的限制[5-6].
在局域網(wǎng)聊天系統(tǒng)中,擁有大量的客戶,網(wǎng)絡(luò)負(fù)擔(dān)重,對(duì)響應(yīng)速度要求高,同時(shí)網(wǎng)絡(luò)數(shù)據(jù)大多為短消息,對(duì)數(shù)據(jù)安全性無特殊要求,使用UDP的無連接服務(wù)是有意義的.
在Linux 環(huán)境下,兩個(gè)進(jìn)程間進(jìn)行通信,常用的標(biāo)準(zhǔn)庫函數(shù)為[7-9]:
(1)socket ( ):使用此函數(shù),為應(yīng)用程序使用socket創(chuàng)建了一個(gè)socket號(hào),同時(shí)參數(shù)中指定了通信所用的協(xié)議.
(2)bind():socket的客戶端和服務(wù)端可以通過調(diào)用該函數(shù)來配置本地信息,將創(chuàng)建成功的socket號(hào)與本地地址和端口綁定,此時(shí)三元組{協(xié)議,本地地址,本地端口}確定,這是socket在全網(wǎng)唯一的標(biāo)志.
(3)sendto( ):若源進(jìn)程要發(fā)送數(shù)據(jù),使用此函數(shù),指定目的端的IP地址和端口,建立完整的相關(guān),可以將緩沖區(qū)中的數(shù)據(jù)發(fā)送到指定的接收進(jìn)程.
(4)recvfrom( ):若進(jìn)程要接收信息,使用此函數(shù),指定源端的IP地址和端口,可以將socket緩沖區(qū)中的數(shù)據(jù)接收.
(5)close():數(shù)據(jù)的收發(fā)工作全部完成,關(guān)閉socket時(shí)使用此函數(shù).
在客戶/服務(wù)器模式下,UDP socket編程的基本過程如圖2所示[10].
圖2 socket編程過程圖
局域網(wǎng)聊天系統(tǒng)主要為局域網(wǎng)內(nèi)的用戶提供信息交流的平臺(tái),實(shí)現(xiàn)局域網(wǎng)內(nèi)部通信的目的.作為局域網(wǎng)內(nèi)的通信工具,采用客戶/服務(wù)器體系結(jié)構(gòu),將系統(tǒng)分成服務(wù)器端和客戶端進(jìn)行開發(fā).
聊天系統(tǒng)中不僅包括服務(wù)器與客戶端的通信,還包括客戶端與客戶端的通信.由于每個(gè)客戶都跟服務(wù)器建立了獨(dú)立連接,客戶端之間的通信(包括私聊和群聊),可以借助服務(wù)器完成.對(duì)于私聊,發(fā)送方A先將消息發(fā)給服務(wù)器,再由服務(wù)器把消息轉(zhuǎn)發(fā)給接收方B;對(duì)于群聊,發(fā)送方A先將消息發(fā)給服務(wù)器,再由服務(wù)器把消息發(fā)給所有在線的客戶.
聊天系統(tǒng)的功能如圖3所示:
圖3 聊天系統(tǒng)功能模塊圖
服務(wù)器端主要包括初始化模塊,監(jiān)控模塊和通信處理模塊.初始化模塊完成服務(wù)器端的公共套接字的創(chuàng)建與配置;監(jiān)控模塊監(jiān)控當(dāng)前在線用戶,對(duì)客戶的上線、離線進(jìn)行處理,通過UDP的多播功能把客戶名稱等信息發(fā)送給客戶端,生成客戶列表顯示給客戶;通信處理模塊主要對(duì)客戶的消息進(jìn)行處理,實(shí)現(xiàn)數(shù)據(jù)的發(fā)送與接收.如果服務(wù)器接收不到消息一直處于阻塞狀態(tài),直到收到消息.
客戶端模塊主要包括登錄模塊、刷新模塊、聊天模塊.登錄模塊完成用戶的登錄和初始化客戶界面工作;刷新模塊接收從服務(wù)器傳來的信息,更新用戶列表;聊天模塊完成與單個(gè)客戶的通信和向所有在線客戶發(fā)送消息的功能.
服務(wù)器端:服務(wù)器啟動(dòng)后,使用socket()創(chuàng)建公共socket號(hào),用bind()與IP地址和端口綁定,等待客戶的消息.一旦檢測(cè)到客戶登錄成功,監(jiān)控模塊根據(jù)客戶端的信息更新客戶列表,并反饋給客戶,使客戶得知哪些客戶在線.客戶端就可以與服務(wù)器端進(jìn)行數(shù)據(jù)交換,由通信處理模塊完成聊天的功能,包括群聊和私聊[11].
客戶端:首先調(diào)用連接模塊檢測(cè)服務(wù)器是否在運(yùn)行,若運(yùn)行再登錄.客戶端登錄輸入用戶名,使用socket()創(chuàng)建socket號(hào).用sendto()發(fā)送消息,以告知服務(wù)器在線,然后服務(wù)器返回在線用戶列表.此時(shí),可以進(jìn)入聊天界面.用戶選擇單聊還是群聊,利用聊天模塊,開始數(shù)據(jù)通信.若要結(jié)束,則使用close(),關(guān)閉socket.
局域網(wǎng)聊天系統(tǒng)采用C語言作為編程語言,下面是服務(wù)器端和客戶端的部分源代碼.
服務(wù)器端:
int main()
{
pub_sockfd = socket(AF_INET,SOCK_DGRAM,0);//服務(wù)器端創(chuàng)建數(shù)據(jù)報(bào)socket
if(pub_sockfd < 0)
{perror("socket error");
exit(1);
}
ser_addr.sin_family = AF_INET;//指定協(xié)議族為TCP/IP協(xié)議
ser_addr.sin_port = htons(PORT);//PORT為指定的端口
ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);// 指定本機(jī)IP地址
bind(pub_sockfd,(struct sockaddr *)&ser_addr,sizeof(ser_addr));//將socket與本地IP地址和端口綁定
……
}
客戶端主要代碼:
void client_sock( )
{
……
sockfd_client = socket(AF_INET,SOCK_DGRAM,0);//客戶端創(chuàng)建數(shù)據(jù)報(bào)socket
……
cliaddr.sin_family = AF_INET;
cliaddr.sin_port = htons(PORT);// 設(shè)置服務(wù)器的端口
cliaddr.sin_addr.s_addr = inet_addr(SER_IP);// 指定服務(wù)器的IP地址
ret = sendto(sockfd_client,&cmd,sizeof(struct cli_send_cmd),0,(struct sockaddr *)&cliaddr,sizeof(cliaddr))//客戶端向服務(wù)器端發(fā)送消息
……
ret = recvfrom(sockfd_client,buf,1024,0,(struct sockaddr *)&cliaddr,&cli_len);
/*接收從服務(wù)器端發(fā)來的消息*/
……
}
圖4為系統(tǒng)運(yùn)行時(shí)私聊的界面.
圖4 測(cè)試界面
本文在Linux環(huán)境下,將基于數(shù)據(jù)報(bào)協(xié)議UDP的socket應(yīng)用到局域網(wǎng)聊天系統(tǒng)中,使局域網(wǎng)聊天系統(tǒng)在減少資源開銷的同時(shí),加快了響應(yīng)的速度,可以同時(shí)支持更多的用戶在線.基于UDP的socket是收發(fā)信息的理想選擇,其在網(wǎng)絡(luò)中的應(yīng)用值得進(jìn)一步去探究.
[1]王繼魁.Linux下基于shell腳本的聊天工具[J].吉林師范大學(xué)學(xué)報(bào)(自然科學(xué)版),2009,30(1):122~124.
[2]賈紅偉,葉文來.嵌入式操作系統(tǒng)與嵌入式Linux[J].吉林師范大學(xué)學(xué)報(bào)(自然科學(xué)版),2005,26(3):97~99.
[3]周小松,朱雄軍.基于UOP協(xié)議的Socket網(wǎng)絡(luò)編程模式的實(shí)現(xiàn)[J].武漢職業(yè)技術(shù)學(xué)院學(xué)報(bào),2007,6:84~86.
[4]陳健葦.基于Winsock的局域網(wǎng)聊天室設(shè)計(jì)與實(shí)現(xiàn)[J].數(shù)學(xué)技術(shù)與應(yīng)用,2013,(2):134~136.
[5]吳培賢.Linux環(huán)境下基于UDP的socket編程淺析[J].網(wǎng)絡(luò)安全技術(shù)與應(yīng)用,2006,(1):63~66.
[6]杜經(jīng)緯,王春紅.在P2P網(wǎng)絡(luò)環(huán)境下基于UDP協(xié)議穿越NAT研究[J].吉林師范大學(xué)學(xué)報(bào)(自然科學(xué)版),2012,33(1):93~95.
[7]朱 斌.Linux Socket編程及其在無線網(wǎng)關(guān)中的應(yīng)用[J].微計(jì)算機(jī)信息,2007,23:70~74.
[8]鄒 月,陳建兵.Socket 的網(wǎng)絡(luò)編程研究與實(shí)現(xiàn)[J].電腦編程技巧與維護(hù),2008,(1):11~12.
[9]周西峰,陸 鵬,郭前崗.利用Socket實(shí)現(xiàn)Windows與Linux平臺(tái)間的網(wǎng)絡(luò)通信[J].微型機(jī)與應(yīng)用,2013,18:49~51.
[10]劉 燁.用Socket實(shí)現(xiàn)基于TCP和UPP的原理探索[J].電腦學(xué)習(xí),2009,(6):6~7.
[11]蕭泳東,肖 化.基于Linux的網(wǎng)絡(luò)聊天系統(tǒng)設(shè)計(jì)[J].現(xiàn)代電子技術(shù),2013,(3):51~54.