討論完後,才發現,自己雖然熟悉socket的程式設計套路,但是卻並不是那麼清楚socket的原理,今天就趁這個機會,把有關socket程式設計的幾個疑問給搞清楚吧。
先給出乙個典型的tcp/ip通訊示意圖。
問題一:socket結構體物件究竟是怎樣定義的?
我們知道,在使用socket程式設計之前,需要呼叫socket函式建立乙個socket物件,該函式返回該socket物件的描述符。
函式原型:int socket(int domain, int type, int protocol);那麼,這個socket物件究竟是怎麼定義的呢?它記錄了哪些資訊呢?只記錄了本機ip及埠、還是目的ip及埠、或者都記錄了?
關於這個問題,大家可以在核心原始碼裡面找,也可以參考這篇文章《struct socket 結構詳解》,我們可以看到 socket 結構體的定義如下:
struct socket其中,struct sock 包含有乙個 sock_common 結構體,而sock_common結構體又包含有struct inet_sock 結構體,而struct inet_sock 結構體的部分定義如下:;
struct inet_sock由此,我們清楚了,socket結構體不僅僅記錄了本地的ip和埠號,還記錄了目的ip和埠。
問題二:connect函式究竟做了些什麼操作?
在tcp客戶端,首先呼叫乙個socket()函式,得到乙個socket描述符socketfd,然後通過connect函式對伺服器進行連線,連線成功後,就可以利用這個socketfd描述符使用send/recv函式收發資料了。
關於connect函式和send函式的原型如下:
int connect( int sockfd, const struct sockaddr* server_addr, socklen_t addrlen)那麼,現在的困惑是,為什麼send函式僅僅傳入sockfd就可以知道伺服器的ip和埠號?int send( int sockfd, const void *msg,int len,int flags);
其實,由「問題一」中的答案我們已經很清楚了,sockfd 描述符所描述的socket物件不僅包含了本地ip和埠,同時也包含了伺服器的ip和埠,這樣,才能使得send函式只需要傳入sockfd 即可知道該把資料發向什麼地方。而**中,目的ip和埠只是在connect函式**現過,因此,肯定是connect函式在成功建立連線後,將目的ip和埠寫入了sockfd 描述符所描述的socket物件中。
問題三: accept函式產生的socket有沒有占用新的埠?
首先,回顧一下accept函式,原型如下:
/* 引數:sockfd 監聽套接字,即伺服器端建立的用於listen的socket描述符。accept函式主要用於伺服器端,一般位於listen函式之後,缺省會阻塞程序,直到有乙個客戶請求連線,建立好連線後,它返回的乙個新的套接字 socketfd_new ,此後,伺服器端即可使用這個新的套接字socketfd_new與該客戶端進行通訊,而sockfd 則繼續用於監聽其他客戶端的連線請求。* 引數:len 描述 addr 的長度
*/ int accept(int sockfd, struct sockaddr* addr, socklen_t* len)
至此,我的困惑產生了,這個新的套接字 socketfd_new 與監聽套接字sockfd 是什麼關係?它所代表的socket物件包含了哪些資訊?socketfd_new 是否占用了新的埠與客戶端通訊?
先簡單分析一番,由於**的伺服器也是一種tcp伺服器,使用的是80埠,並不會因客戶端的連線而產生新的埠給客戶端服務,該客戶端依然是向伺服器端的80埠傳送資料,其他客戶端依然向80埠申請連線。因此,可以判斷,socketfd_new 並沒有占用新的埠與客戶端通訊,依然使用的是與監聽套接字socketfd_new一樣的埠號。
那這麼說,難道乙個埠可以被兩個socket物件繫結?當客戶端傳送資料過來的時候,究竟是與哪乙個socket物件通訊呢?
我是這麼理解的(歡迎拍磚)。
首先,乙個埠肯定只能繫結乙個socket。我認為,伺服器端的埠在bind的時候已經繫結到了監聽套接字socetfd所描述的物件上,accept函式新建立的socket物件其實並沒有進行埠的占有,而是複製了socetfd的本地ip和埠號,並且記錄了連線過來的客戶端的ip和埠號。
那麼,當客戶端傳送資料過來的時候,究竟是與哪乙個socket物件通訊呢?
客戶端傳送過來的資料可以分為2種,一種是連線請求,一種是已經建立好連線後的資料傳輸。
由於tcp/ip協議棧是維護著乙個接收和傳送緩衝區的。在接收到來自客戶端的資料報後,伺服器端的tcp/ip協議棧應該會做如下處理:如果收到的是請求連線的資料報,則傳給監聽著連線請求埠的socetfd套接字,進行accept處理;如果是已經建立過連線後的客戶端資料報,則將資料放入接收緩衝區。這樣,當伺服器端需要讀取指定客戶端的資料時,則可以利用socketfd_new 套接字通過recv或者read函式到緩衝區裡面去取指定的資料(因為socketfd_new代表的socket物件記錄了客戶端ip和埠,因此可以鑑別)。
socket的accept函式解析
今天與同學爭執乙個話題 由於socket的accept函式在有客戶端連線的時候產生了新的socket用於服務該客戶端,那麼,這個新的socket到底有沒有占用乙個新的埠?討論完後,才發現,自己雖然熟悉socket的程式設計套路,但是卻並不是那麼清楚socket的原理,今天就趁這個機會,把有關sock...
socket通訊 accept函式
先給出乙個典型的tcp ip通訊示意圖。問題一 socket結構體物件究竟是怎樣定義的?我們知道,在使用socket程式設計之前,需要呼叫socket函式建立乙個socket物件,該函式返回該socket物件的描述符。函式原型 intsocket intdomain,inttype,intproto...
關於accept得到的socket本地埠
伺服器端accept得到的socket本地埠就是listen埠 客戶端如果不指定會隨機乙個本地埠 因此伺服器端沒有連線數量的限制 硬體無限 客戶端最多不能超過65533個連線 今天與同學爭執乙個話題 由於socket的accept函式在有客戶端連線的時候產生了新的socket用於服務該客戶端,那麼,...