前一篇文章,
linux程序間通訊——使用流套接字介紹了一些有關socket(套接字)的一些基本內容,並講解了流套接字的使用,這篇文章將會給大家講講,資料報套接字的使用。
一、簡單回顧——什麼是資料報套接字。
socket,即套接字是一種通訊機制,憑藉這種機制,客戶/伺服器(即要進行通訊的程序)系統的開發工作既可以在本地單機上進行,也可以跨網路進行。也就是說它可以讓不在同一臺計算機但通過網路連線計算機上的程序進行通訊。也因為這樣,套接字明確地將客戶端和伺服器區分開來。
相對於流套接字,資料報套接字的使用更為簡單,它是由型別sock_dgram指定的,它不需要建立連線和維持乙個連線,它們在af_inet中通常是通過udp/ip協議實現的。它對可以傳送的資料的長度有限制,資料報作為乙個單獨的網路訊息被傳輸,它可能會丟失、複製或錯亂到達,udp不是乙個可靠的協議,但是它的速度比較高,因為它並一需要總是要建立和維持乙個連線。
二、基於流套接字的客戶/伺服器的工作流程
使用資料報socket進行程序通訊的程序採用的客戶/伺服器系統是如何工作的呢?
1、伺服器端
與使用流套接字一樣,首先伺服器應用程式用系統呼叫socket來建立乙個套接安,它是系統分配給該伺服器程序的類似檔案描述符的資源,它不能與其他的程序共享。
接下來,伺服器程序會給套接字起個名字(監聽),我們使用系統呼叫bind來給套接字命名。然後伺服器程序就開始等待客戶連線到這個套接字。
不同的是,然後系統呼叫recvfrom來接收來自客戶程式傳送過來的資料。伺服器程式對資料進行相應的處理,再通過系統呼叫sendto把處理後的資料傳送回客戶程式。
與流套接字程式相比:
1、在流套接字中的程式中,接收資料是通過系統呼叫read,而傳送資料是通過系統呼叫write來實現,而在資料報套接字程式中,這是通過recvfrom和sendto呼叫來實現的。
2、使用資料報套接字的伺服器程式並不需要listen呼叫來建立乙個佇列來儲存連線,也不需要accept呼叫來接收連線並建立乙個新的socket描述符
2、客戶端
基於資料報socket的客戶端比伺服器端簡單,同樣,客戶應用程式首先呼叫socket來建立乙個未命名的套接字,與伺服器一樣,客戶也是通過sendto和recvfrom來向伺服器傳送資料和從伺服器程式接收資料。
與流套接字程式相比:
使用資料報套接字的客戶程式並不需要使用connect系統呼叫來連線伺服器程式,它只要在需要時向伺服器所監聽的ip埠傳送資訊和接收從伺服器傳送回來的資料即可。
三、資料報socket的介面及作用
socket的介面函式宣告在標頭檔案sys/types.h和sys/socket.h中。
1、建立套接字——socket系統呼叫
該函式用來建立乙個套接字,並返回乙個描述符,該描述符可以用來訪問該套接字,它的原型如下:
[cpp]view plain
copy
print?
int socket(int domain, int type, int protocol);
函式中的三個引數分別對應前面所說的三個套接字屬性。protocol引數設定為0表示使用預設協議。
2、命名(繫結)套接字——bind系統呼叫
該函式把通過socket呼叫建立的套接字命名,從而讓它可以被其他程序使用。對於af_unix,呼叫該函式後套接字就會關聯到乙個檔案系統路徑名,對於af_inet,則會關聯到乙個ip埠號。函式原型如下:
[cpp]view plain
copy
print?
int bind( int socket, const struct sockaddr *address, size_t address_len);
成功時返回0,失敗時返回-1;
3、傳送資料——sendto系統呼叫
該函式把緩衝區buffer中的資訊給送給指定的ip埠的程式,原型如下:
[cpp]view plain
copy
print?
int sendto(int sockfd, void *buffer, size_t len, int flags, struct sockaddr *to, socklen_t tolen);
buffer中儲存著將要傳送的資料,len是buffer的長度,而flags在應用中通常被設定為0,to是要傳送資料到的程式的ip埠,tolen是to引數的長度。
成功時返回傳送的資料的位元組數,失敗時返回-1.
4、接收資料——recvfrom系統呼叫
[cpp]view plain
copy
print?
int recvfrom(int sockfd, void *buffer, size_t len,int flags, struct sockaddr *src_from, socklen_t *src_len);
buffer用於儲存接收到的資料,len指定buffer的長度,而flags在應用中通常被設定0,src_from若不為空,則記錄資料**程式的ip埠,若src_len不為空,則其長度資訊記錄在src_len所指向的變數中。
注意:預設情況下,recvfrom是乙個阻塞的呼叫,即直到它接收到資料才會返回。
5、關閉socket——close系統呼叫
該系統呼叫用來終止伺服器和客戶上的套接字連線,我們應該總是在連線的兩端(伺服器和客戶)關閉套接字。
四、程序使用資料報socket進行通訊
下面用多個客戶程式例項和乙個伺服器程式來演示多個程序如何通過使用資料報socket來進行通訊。
sockserver2.c是乙個伺服器程式,它接收客戶程式發來的資料,並建立乙個子程序來處理客戶傳送過來的資料,處理過程非常簡單,就是把大寫字母改為小寫。然後把處理後的資料(大寫字母對應的小寫字母)傳送回給客戶端。
sockclient2.c是乙個客戶程式,它向伺服器程式傳送資料,並接收伺服器傳送過來的處理後的資料(即小寫字母),然後把接收到的資料輸出到螢幕上。在執行客戶程式時,你可以為它提供乙個字元作為引數,此時客戶程式將把些字元作為要處理的資料傳送給伺服器,如果不提供乙個引數,則預設傳送字元a。
sockserver2.c的源**如下:
[cpp]view plain
copy
print?
#include
#include
#include
#include
#include
#include
#include
int main()
} //關閉套接字
close(server_sockfd);
}
sockclient2.c的源**如下:
[cpp]view plain
copy
print?
#include
#include
#include
#include
#include
#include
int main(int agrc, char *argv)
執行結果如下:
先執行伺服器程式,如下:
再執行三個客戶端:如下:
在本例子中,我們啟動了乙個伺服器程式和三個客戶程式,從執行的結果來看,客戶端傳送給伺服器程式的所有請求都得到了處理,即把大寫字母變成了小寫。recvfrom呼叫是阻塞的呼叫,即只有當接收到資料才會返回。
五、資料報套接字與流套接字的比較
1、從使用的便利和效率來講
我們可以看到使用資料報套接字的確是比使用流套接字簡單,而且快速。
因為使用流套接字的程式,客戶程式需要呼叫connect來建立乙個到伺服器程式的連線,並需要維持這個連線,伺服器程式也需要呼叫listen來建立乙個佇列來儲存未處理的請求,當有資料到達時,伺服器也不需要呼叫accept來接受連線並建立乙個新socket描述符來處理請求。
再來看看使用資料報套接字的程式,伺服器程式與客戶程式所使用的系統呼叫大致相同,伺服器程式只比客戶程式多使用了乙個bind呼叫。基於資料報套接字的程式,只需要使用sendto呼叫來向指定ip埠的程式傳送資訊,使用recvfrom呼叫從指向的ip埠接收資訊即可。因為它並不需要建立乙個連線,接受連線等,所以省去了很多的功夫。
2、從使用場合來講
而資料報套接字是基於udp/ip協議實現的。它對可以傳送的資料的長度有限制,資料報作為乙個單獨的網路訊息被傳輸,它可能會丟失、複製或錯亂到達,udp不是乙個可靠的協議,但是它的速度比較高。所以它比較適合傳送一些對實時性要求較高,但是對安全性和完整性要求不太高的資料。如我們熟悉的聊天資訊,即使有一點的丟失也不會造成理解上的大的問題。
Linux程序間通訊 使用資料報套接字
前一篇文章,linux程序間通訊 使用流套接字 一 簡單回顧 什麼是資料報套接字。socket,即套接字是一種通訊機制,憑藉這種機制,客戶 伺服器 即要進行通訊的程序 系統的開發工作既可以在本地單機上進行,也可以跨網路進行。也就是說它可以讓不在同一臺計算機但通過網路連線計算機上的程序進行通訊。也因為...
Linux程序間通訊 使用匿名管道
在前面,介紹了一種程序間的通訊方式 使用訊號,我們建立通知事件,並通過它引起響應,但傳遞的資訊只是乙個訊號值。這裡將介紹另一種程序間通訊的方式 匿名管道,通過它程序間可以交換更多有用的資料。一 什麼是管道 如果你使用過linux的命令,那麼對於管道這個名詞你一定不會感覺到陌生,因為我們通常通過符號 ...
Linux程序間通訊 使用共享記憶體
一 什麼是共享記憶體 顧名思義。共享記憶體就是同意兩個不相關的程序訪問同乙個邏輯記憶體。共享記憶體是在兩個正在執行的程序之間共享和傳遞資料的一種很有效的方式。不同程序之間共享的記憶體通常安排為同一段物理記憶體。程序能夠將同一段共享記憶體連線到它們自己的位址空間中,全部程序都能夠訪問共享記憶體中的位址...