題目: tcpv4 checksum 筆試題目
- 目標: * 寫一個函式 來計算 包含tcp包的ipv4包checksum,並且返回包含正確的checksum的ipv4包
- 要求: * 只需要計算ipv4和tcp組合在一起的checksum,ipv4的Fragment不用管。不需要處理其他型別其他組合的包的checksum,比如:ipv6不用管,udp不用管,icmp不用管。 * 傳入的 tcp ipv4 包裡面的checksum可能是正確的也可能是錯誤的。呼叫者只需要返回一個其他內容相同,但是checksum正確的 tcp ipv4包 * 函式輸入是一個 帶長度的位元組陣列,函式輸出是一個 帶長度的位元組陣列。 * 可選功能,對輸入包的正確性檢查。 * 如果筆試者選擇不實現該功能,那麼呼叫者會保證輸入的二進位制滿足 ipv4與tcp組合在一起時的有效的包的二進位制陣列,保證不會使用ipv4的fragments功能。 * 如果筆試者選擇實現該功能,那麼呼叫者可能會輸入任意二進位制內容。此時筆試者應該把所有出現錯誤的情況都列印到標準輸出。程式執行過程中不應該出現記憶體溢位,下標越界等無法預料的情況。 * 使用可以滿足上面要求的程式語言都可以。 * 需要寫該函式的自動單元測試,以便證明你的函式的正確性。自動單元測試必須包含後面的 "輸入輸出例子1" 一共1個例子。自動測試的輸入與輸出應該都在你的程式碼裡面,並且自動判斷。 * 該函式應該由你自己獨立完成,該函式的任何部分都不允許複製其他人的程式碼。 * 該函式內部有checksum計算的每一個計算步驟,checksum計算本身不允許直接呼叫庫實現。 * 函式實現可以修改傳入的位元組陣列,也可以不修改傳入的位元組陣列。 * 該函式名稱為 RecomputeChecksum。 * 程式碼應當具有一定的可讀性,人工應當能很輕鬆的找到所有實際執行程式碼的位置。建議避免使用繼承。
- 筆試結果檢查: * 檢查者 執行所有的自動單元測試,檢查是否可以編譯。編譯後執行結果,檢查結果是否完全符合預期,這一步有問題筆試失敗。 * 檢查者 隨機修改某個自動單元測試的某個輸入引數,檢查編譯執行後,結果結果是否執行失敗,這一步有問題筆試失敗。 * 檢查者 加入一個滿足需求並且筆試者不知道的 測試例子,檢查結果是否符合預期,如果這一部分有問題筆試失敗。 * 如果 程式碼不能編譯執行 本次筆試失敗。 * 如果 自動測試執行不符合預期 本次筆試失敗。 * 如果 自動測試不包含後面的 輸入輸出例子1 本次筆試失敗。 * 如果 自動測試的輸入與輸出 沒有包含在程式碼裡面 本次筆試失敗。 * 如果不滿足 獨立完成要求 本次筆試失敗。 * 如果不滿足 包含對每個輸入位元組的實現細節 要求,本次筆試失敗。 * 如果 找不到名為 RecomputeChecksum 的函式,本次筆試失敗。 * 如果 RecomputeChecksum 函式的輸入輸出引數 數量或型別 不滿足要求,本次筆試失敗。 * 如果程式碼可讀性非常差,閱讀程式碼時很難搞清楚實際執行的程式碼的位置,則本次筆試失敗,此項由檢查者決定是否通過。 * 人工閱讀 自動單元測試程式碼以及實現的程式碼,檢查是否 滿足目標和要求。 * 自動測試 裡面覆蓋的細節全面,筆試分數有大量加分。 * 檢查輸入的包是否正確,任意二進位制輸入都能正確錯誤處理,而且程式不會出現記憶體溢位,下標越界等無法預料的情況,筆試分數有大量加分。 * 程式碼複雜度低,程式碼易於理解,筆試分數有少量加分。 * 使用 golang 語言,筆試分數有少量加分。 * 程式碼檔案使用 utf8無bom 編碼,筆試分數有少量加分。
- 參考: * ipv4 checksum https://tools.ietf.org/html/rfc1071 * tcp https://tools.ietf.org/html/rfc793 * tcp checksum https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_checksum_for_IPv4
- 直接返回輸入的函式定義: * go語言版本: func RecomputeChecksum(in []byte)(out []byte){ return in }
* c語言版本: typedef struct Slice{ int len; unsigned char* data; } Slice; Slice RecomputeChecksum(Slice in){ Slice output = {}; output.len = in.len; output.data = in.data; return output; }
* c++語言 應該使用和 c語言完全一致的輸入輸出介面。(在輸入輸出介面上仍然使用struct,不使用類)
* js語言版本:(傳入傳出引數型別都是 Uint8Array 型別) function RecomputeChecksum(inPara){ var outBuffer = new Uint8Array(inPara.length); for (var i=0;i<inPara.length;i++){ outBuffer[i] = inPara[i]; } return outBuffer }
- 輸入與輸出例子: * 輸入與輸出例子1(後面使用的是golang語法): * 輸入: []byte{0x45,0x00,0x00,0x8c,0x28,0xd1,0x00,0x00,0xff,0x06,0x00,0x00,0x73,0xef,0xd2,0x1b, 0xac,0x15,0x00,0x01,0x00,0x50,0xe7,0xa3,0x93,0x2d,0xac,0xdb,0x9d,0x0e,0x0f,0x41, 0x50,0x10,0xff,0xff,0x00,0x00,0x00,0x00,0x34,0x70,0x78,0x3b,0x70,0x61,0x64,0x64, 0x69,0x6e,0x67,0x2d,0x6c,0x65,0x66,0x74,0x3a,0x31,0x30,0x70,0x78,0x3b,0x70,0x61, 0x64,0x64,0x69,0x6e,0x67,0x2d,0x72,0x69,0x67,0x68,0x74,0x3a,0x31,0x30,0x70,0x78, 0x3b,0x63,0x75,0x72,0x73,0x6f,0x72,0x3a,0x64,0x65,0x66,0x61,0x75,0x6c,0x74,0x3b, 0x6f,0x76,0x65,0x72,0x66,0x6c,0x6f,0x77,0x3a,0x68,0x69,0x64,0x64,0x65,0x6e,0x3b, 0x77,0x68,0x69,0x74,0x65,0x2d,0x73,0x70,0x61,0x63,0x65,0x3a,0x6e,0x6f,0x77,0x72, 0x61,0x70,0x7d,0x2e,0x63,0x2d,0x64,0x72,0x6f,0x70,0x64,0x6f,} * 輸出: []byte{0x45,0x00,0x00,0x8c,0x28,0xd1,0x00,0x00,0xff,0x06,0xa0,0x79,0x73,0xef,0xd2,0x1b, 0xac,0x15,0x00,0x01,0x00,0x50,0xe7,0xa3,0x93,0x2d,0xac,0xdb,0x9d,0x0e,0x0f,0x41, 0x50,0x10,0xff,0xff,0xff,0xe6,0x00,0x00,0x34,0x70,0x78,0x3b,0x70,0x61,0x64,0x64, 0x69,0x6e,0x67,0x2d,0x6c,0x65,0x66,0x74,0x3a,0x31,0x30,0x70,0x78,0x3b,0x70,0x61, 0x64,0x64,0x69,0x6e,0x67,0x2d,0x72,0x69,0x67,0x68,0x74,0x3a,0x31,0x30,0x70,0x78, 0x3b,0x63,0x75,0x72,0x73,0x6f,0x72,0x3a,0x64,0x65,0x66,0x61,0x75,0x6c,0x74,0x3b, 0x6f,0x76,0x65,0x72,0x66,0x6c,0x6f,0x77,0x3a,0x68,0x69,0x64,0x64,0x65,0x6e,0x3b, 0x77,0x68,0x69,0x74,0x65,0x2d,0x73,0x70,0x61,0x63,0x65,0x3a,0x6e,0x6f,0x77,0x72, 0x61,0x70,0x7d,0x2e,0x63,0x2d,0x64,0x72,0x6f,0x70,0x64,0x6f,}
複製程式碼