C 構造TCP報文

2021-09-30 08:26:14 字數 3444 閱讀 2464

c# 構造tcp報文段

tcp選項

每個選項的開始是1位元組的kind欄位,說明選項的型別。

kind=0:選項表結束(1位元組)

kind=1:無操作(1位元組)

kind=2:最大報文段長度(4位元組)

kind=3:視窗擴大因子(4位元組)

kind=8:時間戳(10位元組)

3、視窗擴**項:

視窗擴**項使tcp的視窗定義從16位增加到32位,這並不是通過修改tcp首部來實現的,tcp首部仍然使用16位,而是通過定義乙個選項實現對16位的擴大操作來完成的。

4、時間戳選項:

時間戳選項使傳送方在每個報文段中放置乙個時間戳值。接收方在確認中返回這個數值,從而允許傳送方為每乙個收到的ack計算rtt。

其實如果要自己實現乙個tcp通訊過程是相當麻煩的一件事情:

(1)傳送乙個要建立連線的tcp報文;(2)接收到對方同意建立連線的報文;(3)傳送乙個確認連線的報文;(4)收發資料;(5)傳送釋放連線的報文;(6)接收對方同意釋放連線的報文;(7)接收對方釋放連線的報文;(8)傳送乙個同意釋放連線的報文。

還有流量控制、差錯控制、計時器的問題……

下面給出的函式僅僅是根據給出的所有引數構造tcp報文的位元組流。

public byte 構造tcp報文段(uint32 源ip, uint32 目的ip, //這是為了計算校驗和

uint16 源埠號, uint16 目的埠號, uint32 序列號, uint32 確認號,

byte urg, byte ack, byte psh, byte rst, byte syn, byte fin,

uint16 視窗大小, uint16 緊急指標,

byte 選項與填充部分,

byte 資料部分)

uint16 選項與填充部分的長度 = (uint16)選項與填充部分.length;

uint16 資料部分的長度 = (uint16)資料部分.length;

uint16 tcp總長度 = (uint16)(20 + 選項與填充部分的長度 + 資料部分的長度);

byte tcpbytes = new byte[tcp總長度];

uint16 校驗和 = 0;

//網路位元組順序

源ip = (uint)ipaddress.hosttonetworkorder((int)源ip);

目的ip = (uint)ipaddress.hosttonetworkorder((int)目的ip);

源埠號 = (ushort)ipaddress.hosttonetworkorder((int16)源埠號);

目的埠號 = (ushort)ipaddress.hosttonetworkorder((int16)目的埠號);

序列號 = (uint)ipaddress.hosttonetworkorder((int)序列號);

確認號 = (uint)ipaddress.hosttonetworkorder((int)確認號);

視窗大小 = (ushort)ipaddress.hosttonetworkorder((int16)視窗大小);

緊急指標 = (ushort)ipaddress.hosttonetworkorder((int16)緊急指標);

//填充位元組組

bitconverter.getbytes(源埠號).copyto(tcpbytes, 0);//填入源埠號

bitconverter.getbytes(目的埠號).copyto(tcpbytes, 2);//填入目的埠號

bitconverter.getbytes(序列號).copyto(tcpbytes, 4);//填入序列號

bitconverter.getbytes(確認號).copyto(tcpbytes, 8);//

//頭部長度和標誌位的處理

byte 頭部長度 = (byte)((20 + 選項與填充部分的長度) / 4);

頭部長度 <<= 4;//左移4位,餘下部分為0

tcpbytes[12] = 頭部長度;

urg <<= 5; ack <<= 4; psh <<= 3; rst <<= 2; syn <<= 1; fin = (byte)(urg + ack + psh + rst + syn + fin);

tcpbytes[13] = fin;

bitconverter.getbytes(視窗大小).copyto(tcpbytes, 14);//

bitconverter.getbytes(校驗和).copyto(tcpbytes, 16);//校驗和

bitconverter.getbytes(緊急指標).copyto(tcpbytes, 18);//

if (選項與填充部分的長度 > 0) 選項與填充部分.copyto(tcpbytes, 20);

if (資料部分的長度 > 0) 資料部分.copyto(tcpbytes, 20 + 選項與填充部分的長度);

//下面是計算校驗和

byte 偽報文 = new byte[12 + (tcp總長度 + 1) / 2 * 2];//如果不夠偶數個位元組要補上0

bitconverter.getbytes(源ip).copyto(偽報文, 0);//填入源埠號

bitconverter.getbytes(目的ip).copyto(偽報文, 4);//填入目的埠號

偽報文[8] = 0;//填充0.網路位元組順序

偽報文[9] = 6;//和tcp協議號

tcp總長度 = (ushort)ipaddress.hosttonetworkorder((int16)tcp總長度);//網路位元組順序

bitconverter.getbytes(tcp總長度).copyto(偽報文, 10);//填入總長度

tcpbytes.copyto(偽報文, 12);

//string ss = 網路位元組串(偽報文 );//用於除錯檢測

unsafe}

//校驗和 = (ushort)ipaddress.hosttonetworkorder((int16)校驗和);

bitconverter.getbytes(校驗和).copyto(tcpbytes, 16);//校驗和

return tcpbytes;}

unsafe static uint16 計算校驗和(uint16* buffer, int size)

cksum = (cksum >> 16) + (cksum & 0xffff);

cksum += (cksum >> 16);

return (uint16)(~cksum);

}校驗和不需要調整為網路位元組順序,不知道為什麼,可能是調不調整校驗的結果都一樣吧

TCP 報文結構

注意,注意,注意 2 很多內容來自別人博主,十分感謝,當時摘抄實在太匆忙,有的忘了出處,如有冒犯,侵刪。3 祝各位很閒也有錢。tcp報文是tcp層傳輸的資料單元,也叫報文段。1 埠號 用來標識同一臺計算機的不同的應用程序。tcp報頭中的源埠號和目的埠號同ip資料報中的源ip與目的ip唯一確定一條tc...

TCP報文結構

tcp報文結構 埠號tcp的埠號加上ip確定乙個應用程序。目的埠號 接收方計算機上的應用程式介面。序號和確認號 序號標識本報文段傳送的資料組的第乙個位元組的序號,在tcp中每個位元組乙個序號。確認號表示該確認號之前的額資料正確無誤的收到,確認號只有當ack標識為1時有效。資料偏移 由於tcp頭部包含...

TCP協議報文

源埠和目的埠 用來表示傳送主機的程序和接收主機的程序,實現tcp復用和分用 序號 tcp是面向位元組流的,tcp連線中的每個位元組都按序編號,序號欄位又叫報文段序號,指的是當前報文段的第乙個位元組的序號,比如一報文段的序號欄位為301,資料有100位元組,則序號為301,下乙個報文段應該從401開始...