網路程式設計 socket基本概念

2021-07-01 20:47:34 字數 4679 閱讀 5416

什麼是socket?socket是連線應用程式和網路驅動程式的橋梁,socket在應用程式中建立,通過繫結操作和驅動程式建立聯絡。

什麼是ip位址?在網路上,主機與主機間的通訊,首先需要知道對通訊方主機的名稱。在internet上用ip位址來標記網路裝置。廣義上的主機可以是工作在網路上的工作台、伺服器,路由器。有了ip位址相當於主機有了身份。怎麼查詢本機的ip位址。win+r,開啟執行,輸入cmd,進入命令列視窗

在命令列視窗輸入ipconfig,按enter,出現如上圖。現在我們來解釋下面三個名詞。

子網掩碼:c類ip位址預設為255.255.255.0

預設閘道器:網路間傳遞的關口。

網路協議:類似兩個外國人交流,需要用統一的語言才能溝通。http,dns,ftp,tcp,udp,都是協議。

資料封裝:主機間的傳送資料,首先先打包資料,這過程稱為資料封裝。類似,信件裝上信封。在不同的網路層,加上不同的協議頭。

埠:通過不同的埠號標記不同的活動應用程式,1024以下的埠,預定義的服務:如http,使用80埠。

上面我們已經知道網路中的程序是通過socket來通訊的,那什麼是socket呢?socket起源於unix,而unix/linux基本哲學之一就是「一切皆檔案」,都可以用「開啟open –> 讀寫write/read –> 關閉close」模式來操作。我的理解就是socket就是該模式的乙個實現,socket即是一種特殊的檔案,一些socket函式就是對其進行的操作(讀/寫io、開啟、關閉),這些函式我們在後面進行介紹。

int wsastartup(  word wversionrequestedwsadata wsadata)

作用:一,載入套接字型檔,二是確定socket版本。

載入winsock動態庫

wsacleanup()釋放

int

socket(int domain, int type, int protocol);

socket函式對應於普通檔案的開啟操作。普通檔案的開啟操作返回乙個檔案描述字,而socket()用於建立乙個socket描述符(socket descriptor),它唯一標識乙個socket。這個socket描述字跟檔案描述字一樣,後續的操作都有用到它,把它作為引數,通過它來進行一些讀寫操作。

正如可以給fopen的傳入不同引數值,以開啟不同的檔案。建立socket的時候,也可以指定不同的引數建立不同的socket描述符,socket函式的三個引數分別為:

注意:並不是上面的type和protocol可以隨意組合的,如sock_stream不可以跟ipproto_udp組合。當protocol為0時,會自動選擇type型別對應的預設協議。

當我們呼叫socket建立乙個socket時,返回的socket描述字它存在於協議族(address family,af_***)空間中,但沒有乙個具體的位址。如果想要給它賦值乙個位址,就必須呼叫bind()函式,否則就當呼叫connect()、listen()時系統會自動隨機分配乙個埠。

正如上面所說bind()函式把乙個位址族中的特定位址賦給socket。例如對應af_inet、af_inet6就是把乙個ipv4或ipv6位址和埠號組合賦給socket。

int

bind(int sockfd, const

struct sockaddr *addr, socklen_t addrlen);

函式的三個引數分別為:

通常伺服器在啟動的時候都會繫結乙個眾所周知的位址(如ip位址+埠號),用於提供服務,客戶就可以通過它來接連伺服器;而客戶端就不用指定,有系統自動分配乙個埠號和自身的ip位址組合。這就是為什麼通常伺服器端在listen之前會呼叫bind(),而客戶端就不會呼叫,而是在connect()時由系統隨機生成乙個。

如果作為乙個伺服器,在呼叫socket()、bind

()之後就會呼叫listen()來監聽這個socket,如果客戶端這時呼叫connect()發出連線請求,伺服器端就會接收到這個請求。

int

listen(int sockfd, int backlog);

intconnect(int sockfd, const

struct sockaddr *addr, socklen_t addrlen);

listen函式的第乙個引數即為要監聽的socket描述字,第二個引數為相應socket可以排隊的最大連線個數。socket()函式建立的socket預設是乙個主動型別的,listen函式將socket變為被動型別的,等待客戶的連線請求。

connect函式的第乙個引數即為客戶端的socket描述字,第二引數為伺服器的socket位址,第三個引數為socket位址的長度。客戶端通過呼叫connect函式來建立與tcp伺服器的連線。

tcp伺服器端依次呼叫socket()、bind

()、listen()之後,就會監聽指定的socket位址了。tcp客戶端依次呼叫socket()、connect()

之後就想tcp伺服器傳送了乙個連線請求。tcp伺服器監聽到這個請求之後,就會呼叫accept

()函式取接收請求,這樣連線就建立好了。之後就可以開始網路i/o操作了,即類同於普通檔案的讀寫i/o操作。

int

accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

accept函式的第乙個引數為伺服器的socket描述字,第二個引數為指向struct sockaddr *的指標,用於返回客戶端的協議位址,第三個引數為協議位址的長度。如果accpet成功,那麼其返回值是由核心自動生成的乙個全新的描述字,代表與返回客戶的tcp連線。

注意:accept的第乙個引數為伺服器的socket描述字,是伺服器開始呼叫socket()函式生成的,稱為監聽socket描述字;而accept函式返回的是已連線的socket描述字。乙個伺服器通常通常僅僅只建立乙個監聽socket描述字,它在該伺服器的生命週期內一直存在。核心為每個由伺服器程序接受的客戶連線建立了乙個已連線socket描述字,當伺服器完成了對某個客戶的服務,相應的已連線socket描述字就被關閉。

萬事具備只欠東風,至此伺服器與客戶已經建立好連線了。可以呼叫網路i/o進行讀寫操作了,即實現了網咯中不同程序之間的通訊!網路i/o操作有下面幾組:

我推薦使用recvmsg()/sendmsg()函式,這兩個函式是最通用的i/o函式,實際上可以把上面的其它函式都替換成這兩個函式。它們的宣告如下:

#include ssize_t read(int fd, void *buf, size_t count);

ssize_t write(int fd, const

void *buf, size_t count);

#include #include ssize_t send(int sockfd, const

void *buf, size_t len, int flags);

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t sendto(int sockfd, const

void *buf, size_t len, int flags,

const

struct sockaddr *dest_addr, socklen_t addrlen);

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,

struct sockaddr *src_addr, socklen_t *addrlen);

ssize_t sendmsg(int sockfd, const

struct msghdr *msg, int flags);

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

read函式是負責從fd中讀取內容.當讀成功時,read返回實際所讀的位元組數,如果返回的值是0表示已經讀到檔案的結束了,小於0表示出現了錯誤。如果錯誤為eintr說明讀是由中斷引起的,如果是econnrest表示網路連線出了問題。

write函式將buf中的nbytes位元組內容寫入檔案描述符fd.成功時返回寫的位元組數。失敗時返回-1,並設定errno變數。 在網路程式中,當我們向套接字檔案描述符寫時有倆種可能。1)write的返回值大於0,表示寫了部分或者是全部的資料。2)返回的值小於0,此時出現了錯誤。我們要根據錯誤型別來處理。如果錯誤為eintr表示在寫的時候出現了中斷錯誤。如果為epipe表示網路連線出現了問題(對方已經關閉了連線)。

其它的我就不一一介紹這幾對i/o函式了,具體參見man文件或者baidu、google,下面的例子中將使用到send/recv。

在伺服器與客戶端建立連線之後,會進行一些讀寫操作,完成了讀寫操作就要關閉相應的socket描述字,好比操作完開啟的檔案要呼叫fclose關閉開啟的檔案。

#include int

close

(int fd);

close乙個tcp socket的預設行為時把該socket標記為以關閉,然後立即返回到呼叫程序。該描述字不能再由呼叫程序使用,也就是說不能再作為read或write的第乙個引數。

注意:close操作只是使相應socket描述字的引用計數-1,只有當引用計數為0的時候,才會觸發tcp客戶端向伺服器傳送終止連線請求。

socket程式設計 socket基本概念

socket socket可以看成是使用者程序與核心網路協議棧的程式設計介面,不僅可以用於本機的程序間通訊,也可以用於網路上不同主機的程序間通訊 而管道只能在同一臺主機進行通訊 應用層依靠socket進行資料傳輸,我們不必關心底層的核心,即底層資料的傳輸細節,只關心套介面的存在。可以把套介面看成程序...

Linux網路程式設計 基本概念

網路層 功能應用層 具體功能 表示層會話層 幫助使用者程式建立連線過程 取消連線 的過程 傳輸層傳輸層用來傳輸資料,保證資料能夠有序進行,如果資料不正常,可能進行資料的重發,傳輸資料是以位元組為單位進行傳輸 網路層ip位址管理和路由 最短路徑 網路通訊正常的線路 資料鏈路層 網絡卡驅動的程式,用來 ...

socket基本概念及網路協議模型

流 stream 連線 connection 阻塞 block 非阻塞 non block 同步 synchronous 非同步 asynchronous ip位址 ip位址是internet中唯一的位址標識 ip位址是乙個32位長 將要擴充到128位 每個internet包必須帶有ip位址 子網掩...