看板 C_and_CPP 關於我們 聯絡資訊
我補一些東西 @@ ※ 引述《tropical72 (藍影)》之銘言: : http://pastie.org/2139024 : 恕刪. 小弟 winsock 不強, 只做拋磚引玉之效。 : 首先,之前我查到的 10054 代表的是:server 強制把連線斷掉。 10054 是 reset by peer 或是 reset connection 的意思, 就是 TCP flags 的 RST 被 set.. 跟 server 做 close(s) 不一樣, 是比較 low-level 問題 如果是 server close(s), 那 recv() 最終會先得到 0 才對 常見的reset可能有幾種情形 a. connect 時, server 在網路上, 但該 port 沒有開, 會由os直接回 rest 讓client斷線, 省得client要等到timeout浪費時間.. (有時因為安全的考慮, server也有可能故意不回, 避免被掃port) b. tcp SN或之類的東西不sync了, 像是socket被重開了等等 建議原po可以拿像telnet類的工具連連看, 如果也是reset可能是server端的問題 或是有什麼防火牆做怪 : recv(s, recv_buf, MAXLINE, 0)) == 0 : 我無法確定 server 要丟過來的訊息有多大,剛試 ptt.cc (140.112.172.11) : 在進入 do-while 前必須收二次才能把所有歡迎畫面 收完 (設定 MAXLINE 為 20000), 寫TCP程式, 要有幾點要注意, 不然很容易出問題 1. send是send, recv是recv, 兩個獨立的stream send彼此之間, 或recv後此之間有序, 但send/recv之間沒有 2. 一次 send 可能被多次 recv, 多次 send 可能被一次 recv 所以buffer開多大能不能一次收完, 反而不是重點 像 telnet 這種, 就是有資料就收, 沒資料就卡.. 有些protocol是會有 header 的, 所以可以用 header裡的length去決定還要收多少 才會是一個完整的boundary 多收到的就留著, 要跟下次合並, 少數就要繼承收完 3. 若是 blocking model (default) ret = send或recv(s, buf, N, 0)); 當 return 時, 有三種可能 i. <0 error ii. =0 close iii. ret>0 && ret <=n <-- 要注意這點, 不保證全部送/收, 所以基本上要用一個 loop 包住 while (len>0) { r = send (s, buf, len, 0); if (r > 0) { buf += r; len -= r; } /* ... 其他略 ... */ } 4. send return, 不表示對方收到, 也不表示資料已經送出 只是已經放進 os的transmission queue, 所以你可以拿buffer去做別的事 如果程式是單純的一來一回 (client request(send), 等server response(recv)) 其實就沒什麼差別了.. : 架構絕對不只一種,但一些連線軟體似乎會用這種概念下去做。 : 比如說 : int try_times=0; : while(1){ : memset(recv_buf, 0, LEN); : recv_flag = false; // 未收到 : _beginthread(my_recv, 0, NULL); : while(!recv_flag && try_times!=TRY_TIMES){ : Sleep(SLEEP_TIMES); : ++try_times; : } 1. 基本上, poll flag 蠻容易出問題的, 因為 varible 可能被 cache 在 register 裡, 像 while (!done); 這種code會變成inifite loop 2. 每次 creat thread, overhead 很大.. 以上兩點合起來, 其實是程式 IO Model 的問題, 常用的大略有下面幾種 1. 若是簡單的console程式, 在 send或recv 完成前, 其實也不能做別的事 用原本的 block-io 就以了 2. 如果有 GUI 的話, 若是在 event handler 內 send/recv 會block住UI thread, user會感覺到UI hang住 所以會用 i. 自已開獨立的 worker thread 做 ii. 用 library/framework提供的 asyn-io api 3. non-block 變成在poll, 不建議 thread怎麼開? 如果是client, 對一個server就開一個 thread 一個是最簡單的方式 因為連線通常不多, 而且一個connection一個thread, context處理比較直觀 但 thread overhead 不小, 大概可以想一想, win32一個thread 1MB stack, 2000個thread就 2GB, 一個process在user-space可以存取的就2G 2000個thread就滿了, 這還不考慮 scheduling的問題 所以就large scale的server(或connection較多的client), 就會用asyn-io + thread poll 搭下面提的 state machine 架構, 但連線的context變成是比較獨立的state, context 維護比較麻煩 : 架構可議性甚大!但重點、該防範的是: : 怎樣不讓 recv / send 被卡死? send 被卡死可能是 server 那裡出包; : 但 recv 被卡死, client 出包機率就更大! 總合以上.. 我是覺得..會卡是正常的 orz 不要卡到UI就是了 |||| : thread 不在此篇討論範圍內,提出之範例使用之 thread 亦不佳。 : 重點在於:防呆、防卡死。 : ------- : 若要自己寫 winsock, 其實還蠻建議自己先寫一份 ser 出來, : 去簡單模擬你的 serv,再寫 client,同時不少人建議下面的東西也要學 : 1. thread : 2. FSM ---> 這個技巧寫 winsock 據說非常好用,日後容易維護。 如果是搭 GUI 的話, 基本上都是用 state machine 會比較好用, 因為 GUI 會有一個 message queue/loop. 是一個很方便同步的機制 : 此篇僅為拋磚引玉,一點意見,參考一下。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 1.169.173.71
cole945:補兩本書,寫winsock的話,建議看MS Press 的 Network 06/29 22:21
cole945:Programming for Microsft Windows, 2nd. Edition 06/29 22:21
cole945:UNIX Network Programming, Vol1的話,蠻值得一讀.. 06/29 22:22
cole945:對socket的觀念很完整 06/29 22:22
tropical72: 神之手出現了, 快拜 !! 06/29 22:24
cole945:別鬧了..我是剛剛被拋出去的磚 orz 06/29 22:51
VictorTom:結果掉下來發現裡面其實是塊玉....XD 06/30 09:25
asoedarren:請問UDP是否也需要檢查接收長度 還是他自己有邊界? 07/02 09:56