国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

FastSocket學習筆記~制定自已的傳輸協議

2019-11-17 02:36:22
字體:
來源:轉載
供稿:網友

FastSocket學習筆記~制定自已的傳輸協議

對于TCP或者UDP來說,它們作于傳輸層的協議,有著自己的標準,或者叫格式,在我們看TCP格式之前先了解一下計算機的基礎知識,字節,它是計算機世界的一個小單位,也是我們可以理會到的,如一個utf-8英文字母表示一個字節(byte),而一個漢字或者一個unicode的英文字母則表示為兩個字節,或者說在計算機中它將占兩個字節的存儲空間。而在編程世界里,通常所說的Int32,Int16,Int64這些是類型的后綴是指它占用的位數(bit,8bit=1byte),即一個int32類型的數字,占用4個字節的存儲空間,其實這在之前的教課書上大家都見過,也都背過,但可能就是沒有用過,學以不至用,不是一件好事,下面就讓大家學以至用一下。

TCP協議格式

TCP各字段的含義

Source Port & Destination Port 如果我們將ip比喻成地址那麼Port可以說是門口了試想一下一座大樓有前門後門側門送貨的門出貨的門倒垃圾的門扔死尸的門等等亂七八糟的門...... 那麼一個IP地址也有著好多個各種功能的port而每一個port都被不同的服務傾聽著就好比看門人一樣。下面是一些常用port和其對應的服務有興趣的朋友可以在linux的/etc/services這個檔案找到它們 ftp-data 20/tcp ftp 21/tcp telnet 23/tcp smtp 25/tcp mail www 80/tcp http # WorldWideWeb HTTP www 80/udp # HyperText Transfer PRotocol pop-3 110/tcp # POP version 3 pop-3 110/udp 其實port號碼可以隨您喜歡任意指定給哪些服務使用但為了避免“找錯門口”的情形出現(除非您故意想躲起來)人們將一些比較常用的服務(Well known services)的port號碼固定下來了。但是在TCP資料傳送過程中可能同時要處理一個以上的封包程式也會建立多個port來避免突。在兩臺主機進行資料傳送的時候來源地的port和目的地的port都必須讓TCP知道才行。 Sequence Number 發送序號。當資料要從一臺主機傳送去另一臺主機的時候發送端會為封包建立起一個初始號碼然後按照所傳送的位元組數依次的遞增上去那麼下一個封包的序號就會使用遞增之後的值來作為它的序號了。這樣接收端就可以根據序號來檢測資料是否接收完整了。 Acknowledgement Number 回應序號。當接收端接收到TCP封包之後通過檢驗確認之後然後會依照發送序號產生一個回應序號發出一個回應封包給發送端這樣接收端就知道剛才的封包已經被成功接收到了。 可是如果由於網路狀況或其它原因當封包的TTL值達到期限時接收端還沒接收到回應序號就會重發該個被以為丟失了的封包。但如果剛好重發封包之後才接收到回應呢這時候接收端就會根據序號來判斷該封包是否被重發送如果是的話很簡單將之丟棄不做任何處理就是了。 Data Offset 這是用來記錄標頭固定長度用的,和IP封包的IHL差不多。如果options沒設定的話,其長度就是20byte,用十六進位表示就是 0x14了。 Reserved 這是保留區間暫時還沒被使用。 Contral Flag 控制標記。一共有六個它們分別是: Urgent data 如果URG為1,表示這是一個攜有緊急資料的封包。 Acknowledgment field significant 如果ACK為1,表示此封包屬于一個要回應的封包。一般都會為1。 Push function 如果PSH為1,此封包所攜帶的數據會直接上傳給上層應用程序而無需經過TCP處理。Reset 如果RST為1,要求重傳。表示要求重新設定封包再重新傳遞。 Synchronize sequence number 如果SYN為1,表示要求雙方進行同步溝通。 No more data for sender (Finish) 如果FIN為1,表示傳送結束,然後雙方發出結束回應進而正式終止一個TCP傳送過程。 Window 我們都知道MS Windows是什么東西,但這里的Window卻非操作系統的“視窗”哦,這里一般稱為“滑動視窗(Sliding Window)”。為什么我們需要使用視窗呢? 正如您剛才看到的TCP封包會通過SQN和ACK序號來確保傳送的正確性,但如果每一個封包都要等上一個封包的回應才被發送出去的話實在是太慢和難以接受的。這樣我們可以利用Sliding Window在傳送兩端劃分出一個范圍,規定出可以一次性發送的最大封包數目。 當TCP傳送建立起來之後兩端都會將window的設定值還原到初始值比方說每次傳送3個封包。然后發送端就一次發送三個封包出去,然后視窗則會往後移動三個封包填補發送出去之封包的空缺。如果接收端夠順利也能一次處理接收下來的三個封包的話,就會告訴發送端的window值為3,但如果接收端太忙或是其它因素影響暫時只能處理兩個封包,那么在視窗里面就剩下一個封包,然后就會告訴發送端window值為2。這個時候發送端就只送出兩個封包而視窗就會往後移動兩個封包填補發送出去的空缺。您明白為什麼這個視窗會“滑動”了吧。其實,Window值是以字節數計算的。Chechsum 當資料要傳送出去的時候發送端會計算好封包資料大小然後得出這個檢驗值封包一起發送當接收端收到封包之後會再對資料大小進行計算看看是否和檢驗值一致如果結果不相稱則被視為殘缺封包會要求對方重發該個封包。 Urgent Pointer 還記得剛才講到Control Flag的時候我們提到一個URG的標記嗎如果URG被設定為一的時候這里就會指示出緊急資料所在位置。不過這種情形非常少見例如當資料流量超出頻寬的時候系統要求網路主機暫緩發送資料所有主機收到這樣的信息都需要優先處理。 Option 這個選項也比較少用。當那些需要使用同步動作的程式如Telnet要處理好終端的交互模式就會使用到option來指定資料封包的大小因為telnet使用的資料封包都很少但又需要即時回應。 Option的長度為0,或32bit的整倍數,如果不足則填充到滿。

自己動手,搞自己的協議格式

[bodyLength int32][id int32][type int16][name char(20)][body byte[]]

下面我們來測試一個協議,為它賦值,模擬一下client和server的發送與接受的過程

            string name = "zzl";            var message = SerializeHelper.SerializeToBinary(new UserDTO { ID = 1, Name = "repositoryUncle" });            int bodyLength = 4 + 4 + 2 + name.Length + message.Length;            byte[] buffer = new byte[bodyLength];            byte[] body = new byte[bodyLength];            #region (發送端)寫入字節流            //write message length            Buffer.BlockCopy(BitConverter.GetBytes(bodyLength), 0, buffer, 0, 4);            //write id.            Buffer.BlockCopy(BitConverter.GetBytes(101), 0, buffer, 4, 4);            //write response type.            Buffer.BlockCopy(BitConverter.GetBytes((short)4), 0, buffer, 8, 2);            //write response name.            Buffer.BlockCopy(Encoding.ASCII.GetBytes(name), 0, buffer, 10, name.Length);            //write response message.            Buffer.BlockCopy(message, 0, buffer, 10 + name.Length, message.Length);            #endregion            #region (接收端)讀字節流            var messageLength = BitConverter.ToInt32(buffer, 0);            var id = BitConverter.ToInt32(buffer, 4);            var type = BitConverter.ToInt16(buffer, 8);            var nameVal = Encoding.ASCII.GetString(buffer, 10, name.Length);            var dataLength = messageLength - 10 - name.Length;            Buffer.BlockCopy(buffer, 10 + name.Length, body, 0, dataLength);            var obj = (UserDTO)SerializeHelper.DeserializeFromBinary(body);            #endregion

我們在測試時,可以設置斷點去觀察一下messageLength,id,type,nameVal,obj等元素的值,是否正確解析了,呵呵。

最后一點要記住,協議并不難,字節流也并不神秘,關鍵在于堅持,不斷的去探索、研究,有了這幾點,再麻煩的事贊也能搞定!


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 惠安县| 泸州市| 拉萨市| 衡水市| 永康市| 腾冲县| 元阳县| 洞口县| 体育| 内丘县| 偃师市| 自贡市| 如皋市| 云霄县| 兴城市| 鄂托克前旗| 安陆市| 大同县| 平果县| 格尔木市| 九江县| 化隆| 望城县| 舟山市| 乌拉特前旗| 瑞金市| 武定县| 通海县| 巍山| 黄骅市| 崇文区| 昌图县| 江西省| 满洲里市| 巴林左旗| 沙河市| 义乌市| 泰宁县| 南平市| 阜平县| 渭南市|