悲劇由此開始,雖然哥們兒國內非知名工科大學畢業,但好歹也是科班cs出身,但大學得過且過,什麼tcp/ip協議,什麼socket了都沒概念。為了做出乙個簡單的支援廣播的websocket server,在網上找了很多相關**,左抄一句,右抄一句,弄了乙個星期竟然還是漏洞百出,除錯不起來,只好從頭來過了,先補一些基本知識,然後再一步步根據原理實現,今天終於實現了絕大部分功能,由此真的感受到了,搞計算機必須得有理論指導實踐,否則只能像個沒頭蒼蠅到處亂撞。
要想理解socket首先得熟悉一下tcp/ip協議族, tcp/ip(transmission control protocol/internet protocol)即傳輸控制協議/網間協議,定義了主機如何連入網際網路及資料如何再它們之間傳輸的標準,
從字面意思來看tcp/ip是tcp和ip協議的合稱,但實際上tcp/ip協議是指網際網路整個tcp/ip協議族。不同於iso模型的七個分層,tcp/ip協議參考模型把所有的tcp/ip系列協議歸類到四個抽象層中
應用層:tftp,http,snmp,ftp,smtp,dns,telnet 等等
傳輸層:tcp,udp
網路層:ip,icmp,ospf,eigrp,igmp
資料鏈路層:slip,cslip,ppp,mtu
每一抽象層建立在低一層提供的服務上,並且為高一層提供服務,看起來大概是這樣子的
估計有興趣開啟此文的同學都對此有一定了解了,加上我也是一知半解,所以就不詳細解釋,有興趣同學可以上網上搜一下資料
維基百科
在tcp/ip協議中兩個網際網路主機通過兩個路由器和對應的層連線。各主機上的應用通過一些資料通道相互執行讀取操作
我們知道兩個程序如果需要進行通訊最基本的乙個前提能能夠唯一的標示乙個程序,在本地程序通訊中我們可以使用pid來唯一標示乙個程序,但pid只在本地唯一,網路中的兩個程序pid衝突機率很大,這時候我們需要另闢它徑了,我們知道ip層的ip位址可以唯一標示主機,而tcp層協議和埠號可以唯一標示主機的乙個程序,這樣我們可以利用ip位址+協議+埠號唯一標示網路中的乙個程序。
能夠唯一標示網路中的程序後,它們就可以利用socket進行通訊了,什麼是socket呢?我們經常把socket翻譯為套接字,socket是在應用層和傳輸層之間的乙個抽象層,它把tcp/ip層複雜的操作抽象為幾個簡單的介面**用層呼叫已實現程序在網路中通訊。
socket起源於unix,在unix一切皆檔案哲學的思想下,socket是一種"開啟—讀/寫—關閉"模式的實現,伺服器和客戶端各自維護乙個"檔案",在建立連線開啟後,可以向自己檔案寫入內容供對方讀取或者讀取對方內容,通訊結束時關閉檔案。
socket是"開啟—讀/寫—關閉"模式的實現,以使用tcp協議通訊的socket為例,其互動流程大概是這樣子的
伺服器根據位址型別(ipv4,ipv6)、socket型別、協議建立socket
伺服器為socket繫結ip位址和埠號
伺服器socket監聽埠號請求,隨時準備接收客戶端發來的連線,這時候伺服器的socket並沒有被開啟
客戶端建立socket
客戶端開啟socket,根據伺服器ip位址和埠號試圖連線伺服器socket
伺服器socket接收到客戶端socket請求,被動開啟,開始接收客戶端請求,直到客戶端返回連線資訊。這時候socket進入阻塞狀態,所謂阻塞即accept()方法一直到客戶端返回連線資訊後才返回,開始接收下乙個客戶端諒解請求
客戶端連線成功,向伺服器傳送連線狀態資訊
伺服器accept方法返回,連線成功
客戶端向socket寫入資訊
伺服器讀取資訊
客戶端關閉
伺服器端關閉
在tcp/ip協議中,tcp協議通過三次握手建立乙個可靠的連線
第一次握手:客戶端嘗試連線伺服器,向伺服器傳送syn包(同步序列編號synchronize sequence numbers),syn=j,客戶端進入syn_send狀態等待伺服器確認
第二次握手:伺服器接收客戶端syn包並確認(ack=j+1),同時向客戶端傳送乙個syn包(syn=k),即syn+ack包,此時伺服器進入syn_recv狀態
第三次握手:第三次握手:客戶端收到伺服器的syn+ack包,向伺服器傳送確認包ack(ack=k+1),此包傳送完畢,客戶端和伺服器進入established狀態,完成三次握手
定睛一看,伺服器socket與客戶端socket建立連線的部分其實就是大名鼎鼎的三次握手
socket程式設計api
前面提到socket是"開啟—讀/寫—關閉"模式的實現,簡單了解一下socket提供了哪些api**用程式使用,還是以tcp協議為例,看看unix下的socket api,其它語言都很類似(php甚至名字都幾乎一樣),這裡我就簡單解釋一下方法作用和引數,具體使用有興趣同學可以看看部落格參考中的鏈結或者上網搜尋
int socket(int domain, int type, int protocol);根據指定的位址族、資料型別和協議來分配乙個socket的描述字及其所用的資源。
domain:協議族,常用的有af_inet、af_inet6、af_local、af_route其中af_inet代表使用ipv4位址
type:socket型別,常用的socket型別有,sock_stream、sock_dgram、sock_raw、sock_packet、sock_seqpacket等
protocol:協議。常用的協議有,ipproto_tcp、ipptoto_udp、ipproto_sctp、ipproto_tipc等
int bind(int sockfd, const把乙個位址族中的特定位址賦給socketstruct sockaddr *addr, socklen_t addrlen);
sockfd:socket描述字,也就是socket引用
addr:要繫結給sockfd的協議位址
addrlen:位址的長度
通常伺服器在啟動的時候都會繫結乙個眾所周知的位址(如ip位址+埠號),用於提供服務,客戶就可以通過它來接連伺服器;而客戶端就不用指定,有系統自動分配乙個埠號和自身的ip位址組合。這就是為什麼通常伺服器端在listen之前會呼叫bind(),而客戶端就不會呼叫,而是在connect()時由系統隨機生成乙個。
int listen(int sockfd, int backlog);監聽socket
sockfd:要監聽的socket描述字
backlog:相應socket可以排隊的最大連線個數
int connect(int sockfd, const連線某個socketstruct sockaddr *addr, socklen_t addrlen);
sockfd:客戶端的socket描述字
addr:伺服器的socket位址
addrlen:socket位址的長度
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);tcp伺服器監聽到客戶端請求之後,呼叫accept()函式取接收請求
sockfd:伺服器的socket描述字
addr:客戶端的socket位址
addrlen:socket位址的長度
ssize_t read(int fd, void *buf, size_t count);讀取socket內容
fd:socket描述字
buf:緩衝區
count:緩衝區長度
ssize_t write(int fd, const向socket寫入內容,其實就是傳送內容void *buf, size_t count);
fd:socket描述字
buf:緩衝區
count:緩衝區長度
int close(int fd);socket標記為以關閉 ,使相應socket描述字的引用計數-1,當引用計數為0的時候,觸發tcp客戶端向伺服器傳送終止連線請求。
linux socket程式設計(不限linux)
揭開socket程式設計的面紗
簡單理解Socket
鏈結 要想理解socket首先得熟悉一下tcp ip協議族,tcp ip transmission control protocol internet protocol 即傳輸控制協議 網間協議,定義了主機如何連入網際網路及資料如何再它們之間傳輸的標準 從字面意思來看tcp ip是tcp和ip協議的...
簡單理解Socket
tcp ip 要想理解socket首先得熟悉一下tcp ip協議族,tcp ip transmission control protocol internet protocol 即傳輸控制協議 網間協議,定義了主機如何連入網際網路及資料如何再它們之間傳輸的標準,從字面意思來看tcp ip是tcp和i...
簡單理解Socket
要想理解socket首先得熟悉一下tcp ip協議族,tcp ip transmission control protocol internet protocol 即傳輸控制協議 網間協議,定義了主機如何連入網際網路及資料如何再它們之間傳輸的標準,從字面意思來看tcp ip是tcp和ip協議的合稱,...