锘??xml version="1.0" encoding="utf-8" standalone="yes"?>
P2P 涔?UDP絀塊廚AT鐨勫師鐞嗕笌瀹炵幇錛堥檮婧愪唬鐮侊級
鍘熷垱錛歴hootingstars
鍙傝冿細http://midcom-p2p.sourceforge.net/draft-ford-midcom-p2p-01.txt
璁哄潧涓婄粡甯告湁瀵筆2P鍘熺悊鐨勮璁猴紝浣嗘槸璁ㄨ褰掕璁猴紝寰堝皯鏈夊疄璐ㄧ殑涓滆タ浜х敓錛堟簮浠g爜錛夈傚懙鍛碉紝鍦ㄨ繖閲屾垜灝辯敤鑷繁瀹炵幇鐨勪竴涓簮浠g爜鏉ヨ鏄嶶DP絀胯秺NAT鐨勫師鐞嗐?br>
棣栧厛鍏堜粙緇嶄竴浜涘熀鏈蹇碉細
NAT(Network Address Translators)錛岀綉緇滃湴鍧杞崲錛氱綉緇滃湴鍧杞崲鏄湪IP鍦板潃鏃ョ泭緙轟箯鐨勬儏鍐典笅浜х敓鐨勶紝瀹冪殑涓昏鐩殑灝辨槸涓轟簡鑳藉鍦板潃閲嶇敤銆侼AT鍒嗕負涓ゅぇ綾伙紝鍩烘湰鐨凬AT鍜孨APT(Network Address/Port Translator)銆?br> 鏈寮濮婲AT鏄繍琛屽湪璺敱鍣ㄤ笂鐨勪竴涓姛鑳芥ā鍧椼?br>
鏈鍏堟彁鍑虹殑鏄熀鏈殑NAT錛屽畠鐨勪駭鐢熷熀浜庡涓嬩簨瀹烇細涓涓鏈夌綉緇滐紙鍩燂級涓殑鑺傜偣涓彧鏈夊緢灝戠殑鑺傜偣闇瑕佷笌澶栫綉榪炴帴錛堝懙鍛碉紝榪欐槸鍦ㄤ笂涓栫邯90騫翠唬涓湡鎻愬嚭鐨勶級銆傞偅涔堣繖涓瓙緗戜腑鍏跺疄鍙湁灝戞暟鐨勮妭鐐歸渶瑕佸叏鐞冨敮涓鐨処P鍦板潃錛屽叾浠栫殑鑺傜偣鐨処P鍦板潃搴旇鏄彲浠ラ噸鐢ㄧ殑銆?br> 鍥犳錛屽熀鏈殑NAT瀹炵幇鐨勫姛鑳藉緢綆鍗曪紝鍦ㄥ瓙緗戝唴浣跨敤涓涓繚鐣欑殑IP瀛愮綉孌碉紝榪欎簺IP瀵瑰鏄笉鍙鐨勩傚瓙緗戝唴鍙湁灝戞暟涓浜汭P鍦板潃鍙互瀵瑰簲鍒扮湡姝e叏鐞冨敮涓鐨?IP鍦板潃銆傚鏋滆繖浜涜妭鐐歸渶瑕佽闂閮ㄧ綉緇滐紝閭d箞鍩烘湰NAT灝辮礋璐e皢榪欎釜鑺傜偣鐨勫瓙緗戝唴IP杞寲涓轟竴涓叏鐞冨敮涓鐨処P鐒跺悗鍙戦佸嚭鍘匯?鍩烘湰鐨凬AT浼氭敼鍙業P 鍖呬腑鐨勫師IP鍦板潃錛屼絾鏄笉浼氭敼鍙業P鍖呬腑鐨勭鍙?
鍏充簬鍩烘湰鐨凬AT鍙互鍙傜湅RFC 1631
鍙﹀涓縐峃AT鍙仛NAPT錛屼粠鍚嶇О涓婃垜浠篃鍙互鐪嬪緱鍑猴紝NAPT涓嶄絾浼氭敼鍙樼粡榪囪繖涓狽AT璁懼鐨処P鏁版嵁鎶ョ殑IP鍦板潃錛岃繕浼氭敼鍙業P鏁版嵁鎶ョ殑 TCP/UDP绔彛銆傚熀鏈琋AT鐨勮澶囧彲鑳芥垜浠鐨勪笉澶氾紙鍛靛懙錛屾垜娌℃湁瑙佸埌榪囷級錛孨APT鎵嶆槸鎴戜滑鐪熸璁ㄨ鐨勪富瑙掋傜湅涓嬪浘錛?br> Server S1
18.181.0.31:1235
|
^ Session 1 (A-S1) ^ |
| 18.181.0.31:1235 | |
v 155.99.25.11:62000 v |
|
NAT
155.99.25.11
|
^ Session 1 (A-S1) ^ |
| 18.181.0.31:1235 | |
v 10.0.0.1:1234 v |
|
Client A
10.0.0.1:1234
鏈変竴涓鏈夌綉緇?0.*.*.*錛孋lient A鏄叾涓殑涓鍙拌綆楁満錛岃繖涓綉緇滅殑緗戝叧錛堜竴涓狽AT璁懼錛夌殑澶栫綉IP鏄?55.99.25.11(搴旇榪樻湁涓涓唴緗戠殑IP鍦板潃錛屾瘮濡?10.0.0.10)銆傚鏋淐lient A涓殑鏌愪釜榪涚▼錛堣繖涓繘紼嬪垱寤轟簡涓涓猆DP Socket,榪欎釜Socket緇戝畾1234绔彛錛夋兂璁塊棶澶栫綉涓繪満18.181.0.31鐨?235绔彛錛岄偅涔堝綋鏁版嵁鍖呴氳繃NAT鏃朵細鍙戠敓浠涔堜簨鎯呭憿錛?br> 棣栧厛NAT浼氭敼鍙樿繖涓暟鎹寘鐨勫師IP鍦板潃錛屾敼涓?55.99.25.11銆傛帴鐫NAT浼氫負榪欎釜浼犺緭鍒涘緩涓涓猄ession錛圫ession鏄竴涓娊璞$殑姒傚康錛屽鏋滄槸TCP錛屼篃璁窼ession鏄敱涓涓猄YN鍖呭紑濮嬶紝浠ヤ竴涓狥IN鍖呯粨鏉熴傝孶DP鍛紝浠ヨ繖涓狪P鐨勮繖涓鍙g殑絎竴涓猆DP寮濮嬶紝緇撴潫鍛紝鍛靛懙錛屼篃璁告槸鍑犲垎閽燂紝涔熻鏄嚑灝忔椂錛岃繖瑕佺湅鍏蜂綋鐨勫疄鐜頒簡錛夊茍涓旂粰榪欎釜Session鍒嗛厤涓涓鍙o紝姣斿62000錛岀劧鍚庢敼鍙樿繖涓暟鎹寘鐨勬簮绔彛涓?2000銆傛墍浠ユ湰鏉ユ槸錛?0.0.0.1:1234->18.181.0.31:1235錛夌殑鏁版嵁鍖呭埌浜嗕簰鑱旂綉涓婂彉涓轟簡錛?55.99.25.11:62000 ->18.181.0.31:1235錛夈?br> 涓鏃AT鍒涘緩浜嗕竴涓猄ession鍚庯紝NAT浼氳浣?2000绔彛瀵瑰簲鐨勬槸10.0.0.1鐨?234绔彛錛屼互鍚庝粠18.181.0.31鍙戦佸埌 62000绔彛鐨勬暟鎹細琚玁AT鑷姩鐨勮漿鍙戝埌10.0.0.1涓娿傦紙娉ㄦ剰錛氳繖閲屾槸璇?8.181.0.31鍙戦佸埌62000绔彛鐨勬暟鎹細琚漿鍙戯紝鍏朵粬鐨?IP鍙戦佸埌榪欎釜绔彛鐨勬暟鎹皢琚玁AT鎶涘純錛夎繖鏍稢lient A灝變笌Server S1寤虹珛浠ヤ簡涓涓繛鎺ャ?br>
鍛靛懙錛屼笂闈㈢殑鍩虹鐭ヨ瘑鍙兘寰堝浜洪兘鐭ラ亾浜嗭紝閭d箞涓嬮潰鏄叧閿殑閮ㄥ垎浜嗐?br> 鐪嬬湅涓嬮潰鐨勬儏鍐碉細
Server S1 Server S2
18.181.0.31:1235 138.76.29.7:1235
| |
| |
+----------------------+----------------------+
|
^ Session 1 (A-S1) ^ | ^ Session 2 (A-S2) ^
| 18.181.0.31:1235 | | | 138.76.29.7:1235 |
v 155.99.25.11:62000 v | v 155.99.25.11:62000 v
|
Cone NAT
155.99.25.11
|
^ Session 1 (A-S1) ^ | ^ Session 2 (A-S2) ^
| 18.181.0.31:1235 | | | 138.76.29.7:1235 |
v 10.0.0.1:1234 v | v 10.0.0.1:1234 v
|
Client A
10.0.0.1:1234
鎺ヤ笂闈㈢殑渚嬪瓙錛屽鏋淐lient A鐨勫師鏉ラ偅涓猄ocket(緇戝畾浜?234绔彛鐨勯偅涓猆DP Socket)鍙堟帴鐫鍚戝彟澶栦竴涓猄erver S2鍙戦佷簡涓涓猆DP鍖咃紝閭d箞榪欎釜UDP鍖呭湪閫氳繃NAT鏃朵細鎬庝箞鏍峰憿錛?br> 榪欐椂鍙兘浼氭湁涓ょ鎯呭喌鍙戠敓錛屼竴縐嶆槸NAT鍐嶆鍒涘緩涓涓猄ession錛屽茍涓斿啀嬈′負榪欎釜Session鍒嗛厤涓涓鍙e彿錛堟瘮濡傦細62001錛夈傚彟澶栦竴縐嶆槸 NAT鍐嶆鍒涘緩涓涓猄ession錛屼絾鏄笉浼氭柊鍒嗛厤涓涓鍙e彿錛岃屾槸鐢ㄥ師鏉ュ垎閰嶇殑绔彛鍙?2000銆傚墠涓縐峃AT鍙仛Symmetric NAT錛屽悗涓縐嶅彨鍋欳one NAT銆傛垜浠湡鏈涙垜浠殑NAT鏄浜岀錛屽懙鍛碉紝濡傛灉浣犵殑NAT鍒氬ソ鏄涓縐嶏紝閭d箞寰堝彲鑳戒細鏈夊緢澶歅2P杞歡澶辯伒銆傦紙鍙互搴嗗垢鐨勬槸錛岀幇鍦ㄧ粷澶у鏁扮殑NAT灞炰簬鍚庤咃紝鍗矯one NAT錛?br>
濂戒簡錛屾垜浠湅鍒幫紝閫氳繃NAT,瀛愮綉鍐呯殑璁$畻鏈哄悜澶栬繛緇撴槸寰堝鏄撶殑錛圢AT鐩稿綋浜庨忔槑鐨勶紝瀛愮綉鍐呯殑鍜屽緗戠殑璁$畻鏈轟笉鐢ㄧ煡閬揘AT鐨勬儏鍐碉級銆?br> 浣嗘槸濡傛灉澶栭儴鐨勮綆楁満鎯寵闂瓙緗戝唴鐨勮綆楁満灝辨瘮杈冨洶闅句簡錛堣岃繖姝f槸P2P鎵闇瑕佺殑錛夈?br> 閭d箞鎴戜滑濡傛灉鎯充粠澶栭儴鍙戦佷竴涓暟鎹姤緇欏唴緗戠殑璁$畻鏈烘湁浠涔堝姙娉曞憿錛熼鍏堬紝鎴戜滑蹇呴』鍦ㄥ唴緗戠殑NAT涓婃墦涓婁竴涓?#8220;媧?#8221;錛堜篃灝辨槸鍓嶉潰鎴戜滑璇寸殑鍦∟AT涓婂緩绔嬩竴涓?Session錛夛紝榪欎釜媧炰笉鑳界敱澶栭儴鏉ユ墦錛屽彧鑳界敱鍐呯綉鍐呯殑涓繪満鏉ユ墦銆傝屼笖榪欎釜媧炴槸鏈夋柟鍚戠殑錛屾瘮濡備粠鍐呴儴鏌愬彴涓繪満錛堟瘮濡傦細192.168.0.10錛夊悜澶栭儴鐨勬煇涓狪P(姣斿錛?19.237.60.1)鍙戦佷竴涓猆DP鍖咃紝閭d箞灝卞湪榪欎釜鍐呯綉鐨凬AT璁懼涓婃墦浜嗕竴涓柟鍚戜負219.237.60.1鐨?#8220;媧?#8221;錛岋紙榪欏氨鏄О涓篣DP Hole Punching鐨勬妧鏈級浠ュ悗219.237.60.1灝卞彲浠ラ氳繃榪欎釜媧炰笌鍐呯綉鐨?92.168.0.10鑱旂郴浜嗐傦紙浣嗘槸鍏朵粬鐨処P涓嶈兘鍒╃敤榪欎釜媧烇級銆?br>
鍛靛懙錛岀幇鍦ㄨ杞埌鎴戜滑鐨勬棰楶2P浜嗐傛湁浜嗕笂闈㈢殑鐞嗚錛屽疄鐜頒袱涓唴緗戠殑涓繪満閫氳灝卞樊鏈鍚庝竴姝ヤ簡錛氶偅灝辨槸楦$敓铔嬭繕鏄泲鐢熼浮鐨勯棶棰樹簡錛屼袱杈歸兘鏃犳硶涓誨姩鍙戝嚭榪炴帴璇鋒眰錛岃皝涔熶笉鐭ラ亾璋佺殑鍏綉鍦板潃錛岄偅鎴戜滑濡備綍鏉ユ墦榪欎釜媧炲憿錛熸垜浠渶瑕佷竴涓腑闂翠漢鏉ヨ仈緋昏繖涓や釜鍐呯綉涓繪満銆?br> 鐜板湪鎴戜滑鏉ョ湅鐪嬩竴涓狿2P杞歡鐨勬祦紼嬶紝浠ヤ笅鍥句負渚嬶細
Server S 錛?19.237.60.1錛?br> |
|
+----------------------+----------------------+
| |
NAT A (澶栫綉IP:202.187.45.3) NAT B (澶栫綉IP:187.34.1.56)
| (鍐呯綉IP:192.168.0.1) | (鍐呯綉IP:192.168.0.1)
| |
Client A (192.168.0.20:4000) Client B (192.168.0.10:40000)
棣栧厛錛孋lient A鐧誨綍鏈嶅姟鍣紝NAT A涓鴻繖嬈$殑Session鍒嗛厤浜嗕竴涓鍙?0000錛岄偅涔圫erver S鏀跺埌鐨凜lient A鐨勫湴鍧鏄?02.187.45.3:60000錛岃繖灝辨槸Client A鐨勫緗戝湴鍧浜嗐傚悓鏍鳳紝Client B鐧誨綍Server S錛孨AT B緇欐嬈ession鍒嗛厤鐨勭鍙f槸40000錛岄偅涔圫erver S鏀跺埌鐨凚鐨勫湴鍧鏄?87.34.1.56:40000銆?br> 姝ゆ椂錛孋lient A涓嶤lient B閮藉彲浠ヤ笌Server S閫氫俊浜嗐傚鏋淐lient A姝ゆ椂鎯崇洿鎺ュ彂閫佷俊鎭粰Client B錛岄偅涔堜粬鍙互浠嶴erver S閭e効鑾峰緱B鐨勫叕緗戝湴鍧187.34.1.56:40000錛屾槸涓嶆槸Client A鍚戣繖涓湴鍧鍙戦佷俊鎭疌lient B灝辮兘鏀跺埌浜嗗憿錛熺瓟妗堟槸涓嶈錛屽洜涓哄鏋滆繖鏍峰彂閫佷俊鎭紝NAT B浼氬皢榪欎釜淇℃伅涓㈠純錛堝洜涓鴻繖鏍風殑淇℃伅鏄笉璇瘋嚜鏉ョ殑錛屼負浜嗗畨鍏紝澶у鏁癗AT閮戒細鎵ц涓㈠純鍔ㄤ綔錛夈傜幇鍦ㄦ垜浠渶瑕佺殑鏄湪NAT B涓婃墦涓涓柟鍚戜負202.187.45.3錛堝嵆Client A鐨勫緗戝湴鍧錛夌殑媧烇紝閭d箞Client A鍙戦佸埌187.34.1.56:40000鐨勪俊鎭?Client B灝辮兘鏀跺埌浜嗐傝繖涓墦媧炲懡浠ょ敱璋佹潵鍙戝憿錛屽懙鍛碉紝褰撶劧鏄疭erver S銆?br> 鎬葷粨涓涓嬭繖涓繃紼嬶細濡傛灉Client A鎯沖悜Client B鍙戦佷俊鎭紝閭d箞Client A鍙戦佸懡浠ょ粰Server S錛岃姹係erver S鍛戒護Client B鍚慍lient A鏂瑰悜鎵撴礊銆傚懙鍛碉紝鏄笉鏄緢緇曞彛錛屼笉榪囨病鍏崇郴錛屾兂涓鎯沖氨寰堟竻妤氫簡錛屼綍鍐佃繕鏈夋簮浠g爜鍛紙渚佸笀璇磋繃錛氬湪婧愪唬鐮侀潰鍓嶆病鏈夌瀵?8錛夛級錛岀劧鍚嶤lient A灝卞彲浠ラ氳繃Client B鐨勫緗戝湴鍧涓嶤lient B閫氫俊浜嗐?br>
娉ㄦ剰錛氫互涓婅繃紼嬪彧閫傚悎浜嶤one NAT鐨勬儏鍐碉紝濡傛灉鏄疭ymmetric NAT錛岄偅涔堝綋Client B鍚慍lient A鎵撴礊鐨勭鍙e凡緇忛噸鏂板垎閰嶄簡錛孋lient B灝嗘棤娉曠煡閬撹繖涓鍙o紙濡傛灉Symmetric NAT鐨勭鍙f槸欏哄簭鍒嗛厤鐨勶紝閭d箞鎴戜滑鎴栬鍙互鐚滄祴榪欎釜绔彛鍙鳳紝鍙槸鐢變簬鍙兘瀵艱嚧澶辮觸鐨勫洜绱犲お澶氾紝鎴戜滑涓嶆帹鑽愯繖縐嶇寽嫻嬬鍙g殑鏂規硶錛夈?br>
涓嬮潰鏄竴涓ā鎷烶2P鑱婂ぉ鐨勮繃紼嬬殑婧愪唬鐮侊紝榪囩▼寰堢畝鍗曪紝P2PServer榪愯鍦ㄤ竴涓嫢鏈夊叕緗慖P鐨勮綆楁満涓婏紝P2PClient榪愯鍦ㄤ袱涓笉鍚岀殑NAT 鍚庯紙娉ㄦ剰錛屽鏋滀袱涓鎴風榪愯鍦ㄤ竴涓狽AT鍚庯紝鏈▼搴忓緢鍙兘涓嶈兘榪愯姝e父錛岃繖鍙栧喅浜庝綘鐨凬AT鏄惁鏀寔loopback translation錛岃瑙乭ttp://midcom-p2p.sourceforge.net/draft-ford-midcom-p2p-01.txt錛屽綋鐒訛紝姝ら棶棰樺彲浠ラ氳繃鍙屾柟鍏堝皾璇曡繛鎺ュ鏂圭殑鍐呯綉IP鏉ヨВ鍐籌紝浣嗘槸榪欎釜浠g爜鍙槸涓轟簡楠岃瘉鍘熺悊錛屽茍娌℃湁澶勭悊榪欎簺闂錛夛紝鍚庣櫥褰曠殑璁$畻鏈哄彲浠ヨ幏寰楀厛鐧誨綍璁$畻鏈虹殑鐢ㄦ埛鍚嶏紝鍚庣櫥褰曠殑璁$畻鏈洪氳繃send username message鐨勬牸寮忔潵鍙戦佹秷鎭傚鏋滃彂閫佹垚鍔燂紝璇存槑浣犲凡鍙栧緱浜嗙洿鎺ヤ笌瀵規柟榪炴帴鐨勬垚鍔熴?br> 紼嬪簭鐜板湪鏀寔涓変釜鍛戒護錛歴end , getu , exit
send鏍煎紡錛歴end username message
鍔熻兘錛氬彂閫佷俊鎭粰username
getu鏍煎紡錛歡etu
鍔熻兘錛氳幏寰楀綋鍓嶆湇鍔″櫒鐢ㄦ埛鍒楄〃
exit鏍煎紡錛歟xit
鍔熻兘錛氭敞閿涓庢湇鍔″櫒鐨勮繛鎺ワ紙鏈嶅姟鍣ㄤ笉浼氳嚜鍔ㄧ洃嫻嬪鎴鋒槸鍚﹀悐綰匡級
浠g爜寰堢煭錛岀浉淇″緢瀹規槗鎳傦紝濡傛灉鏈変粈涔堥棶棰橈紝鍙互緇欐垜鍙戦偖浠秡houhuis22@sina.com 鎴栬呭湪CSDN涓婂彂閫佺煭娑堟伅銆傚悓鏃訛紝嬈㈣繋杞彂姝ゆ枃錛屼絾甯屾湜淇濈暀浣滆呯増鏉?-錛夈?br>
鏈鍚庢劅璋SDN緗戝弸 PiggyXP 鍜?Seilfer鐨勬祴璇曞府鍔?br>
P2PServer.c
/* P2P 紼嬪簭鏈嶅姟绔?br> *
* 鏂囦歡鍚嶏細P2PServer.c
*
* 鏃ユ湡錛?004-5-21
*
* 浣滆咃細shootingstars(zhouhuis22@sina.com)
*
*/
#pragma comment(lib, "ws2_32.lib")
#include "windows.h"
#include "..\proto.h"
#include "..\Exception.h"
UserList ClientList;
void InitWinSock()
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("Windows sockets 2.2 startup");
throw Exception("");
}
else{
printf("Using %s (Status: %s)\n",
wsaData.szDescription, wsaData.szSystemStatus);
printf("with API versions %d.%d to %d.%d\n\n",
LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion),
LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
}
}
SOCKET mksock(int type)
{
SOCKET sock = socket(AF_INET, type, 0);
if (sock < 0)
{
printf("create socket error");
throw Exception("");
}
return sock;
}
stUserListNode GetUser(char *username)
{
for(UserList::iterator UserIterator=ClientList.begin();
UserIterator!=ClientList.end();
++UserIterator)
{
if( strcmp( ((*UserIterator)->userName), username) == 0 )
return *(*UserIterator);
}
throw Exception("not find this user");
}
int main(int argc, char* argv[])
{
try{
InitWinSock();
SOCKET PrimaryUDP;
PrimaryUDP = mksock(SOCK_DGRAM);
sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port= htons(SERVER_PORT);
local.sin_addr.s_addr = htonl(INADDR_ANY);
int nResult=bind(PrimaryUDP,(sockaddr*)&local,sizeof(sockaddr));
if(nResult==SOCKET_ERROR)
throw Exception("bind error");
sockaddr_in sender;
stMessage recvbuf;
memset(&recvbuf,0,sizeof(stMessage));
// 寮濮嬩富寰幆.
// 涓誨驚鐜礋璐d笅闈㈠嚑浠朵簨鎯?
// 涓:璇誨彇瀹㈡埛绔櫥闄嗗拰鐧誨嚭娑堟伅,璁板綍瀹㈡埛鍒楄〃
// 浜?杞彂瀹㈡埛p2p璇鋒眰
for(;;)
{
int dwSender = sizeof(sender);
int ret = recvfrom(PrimaryUDP, (char *)&recvbuf, sizeof(stMessage), 0, (sockaddr *)&sender, &dwSender);
if(ret <= 0)
{
printf("recv error");
continue;
}
else
{
int messageType = recvbuf.iMessageType;
switch(messageType){
case LOGIN:
{
// 灝嗚繖涓敤鎴風殑淇℃伅璁板綍鍒扮敤鎴峰垪琛ㄤ腑
printf("has a user login : %s\n", recvbuf.message.loginmember.userName);
stUserListNode *currentuser = new stUserListNode();
strcpy(currentuser->userName, recvbuf.message.loginmember.userName);
currentuser->ip = ntohl(sender.sin_addr.S_un.S_addr);
currentuser->port = ntohs(sender.sin_port);
ClientList.push_back(currentuser);
// 鍙戦佸凡緇忕櫥闄嗙殑瀹㈡埛淇℃伅
int nodecount = (int)ClientList.size();
sendto(PrimaryUDP, (const char*)&nodecount, sizeof(int), 0, (const sockaddr*)&sender, sizeof(sender));
for(UserList::iterator UserIterator=ClientList.begin();
UserIterator!=ClientList.end();
++UserIterator)
{
sendto(PrimaryUDP, (const char*)(*UserIterator), sizeof(stUserListNode), 0, (const sockaddr*)&sender, sizeof(sender));
}
break;
}
case LOGOUT:
{
// 灝嗘瀹㈡埛淇℃伅鍒犻櫎
printf("has a user logout : %s\n", recvbuf.message.logoutmember.userName);
UserList::iterator removeiterator = NULL;
for(UserList::iterator UserIterator=ClientList.begin();
UserIterator!=ClientList.end();
++UserIterator)
{
if( strcmp( ((*UserIterator)->userName), recvbuf.message.logoutmember.userName) == 0 )
{
removeiterator = UserIterator;
break;
}
}
if(removeiterator != NULL)
ClientList.remove(*removeiterator);
break;
}
case P2PTRANS:
{
// 鏌愪釜瀹㈡埛甯屾湜鏈嶅姟绔悜鍙﹀涓涓鎴峰彂閫佷竴涓墦媧炴秷鎭?br> printf("%s wants to p2p %s\n",inet_ntoa(sender.sin_addr),recvbuf.message.translatemessage.userName);
stUserListNode node = GetUser(recvbuf.message.translatemessage.userName);
sockaddr_in remote;
remote.sin_family=AF_INET;
remote.sin_port= htons(node.port);
remote.sin_addr.s_addr = htonl(node.ip);
in_addr tmp;
tmp.S_un.S_addr = htonl(node.ip);
printf("the address is %s,and port is %d\n",inet_ntoa(tmp), node.port);
stP2PMessage transMessage;
transMessage.iMessageType = P2PSOMEONEWANTTOCALLYOU;
transMessage.iStringLen = ntohl(sender.sin_addr.S_un.S_addr);
transMessage.Port = ntohs(sender.sin_port);
sendto(PrimaryUDP,(const char*)&transMessage, sizeof(transMessage), 0, (const sockaddr *)&remote, sizeof(remote));
break;
}
case GETALLUSER:
{
int command = GETALLUSER;
sendto(PrimaryUDP, (const char*)&command, sizeof(int), 0, (const sockaddr*)&sender, sizeof(sender));
int nodecount = (int)ClientList.size();
sendto(PrimaryUDP, (const char*)&nodecount, sizeof(int), 0, (const sockaddr*)&sender, sizeof(sender));
for(UserList::iterator UserIterator=ClientList.begin();
UserIterator!=ClientList.end();
++UserIterator)
{
sendto(PrimaryUDP, (const char*)(*UserIterator), sizeof(stUserListNode), 0, (const sockaddr*)&sender, sizeof(sender));
}
break;
}
}
}
}
}
catch(Exception &e)
{
printf(e.GetMessage());
return 1;
}
return 0;
}
/* P2P 紼嬪簭瀹㈡埛绔?br> *
* 鏂囦歡鍚嶏細P2PClient.c
*
* 鏃ユ湡錛?004-5-21
*
* 浣滆咃細shootingstars(zhouhuis22@sina.com)
*
*/
#pragma comment(lib,"ws2_32.lib")
#include "windows.h"
#include "..\proto.h"
#include "..\Exception.h"
#include <iostream>
using namespace std;
UserList ClientList;
#define COMMANDMAXC 256
#define MAXRETRY 5
SOCKET PrimaryUDP;
char UserName[10];
char ServerIP[20];
bool RecvedACK;
void InitWinSock()
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("Windows sockets 2.2 startup");
throw Exception("");
}
else{
printf("Using %s (Status: %s)\n",
wsaData.szDescription, wsaData.szSystemStatus);
printf("with API versions %d.%d to %d.%d\n\n",
LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion),
LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
}
}
SOCKET mksock(int type)
{
SOCKET sock = socket(AF_INET, type, 0);
if (sock < 0)
{
printf("create socket error");
throw Exception("");
}
return sock;
}
stUserListNode GetUser(char *username)
{
for(UserList::iterator UserIterator=ClientList.begin();
UserIterator!=ClientList.end();
++UserIterator)
{
if( strcmp( ((*UserIterator)->userName), username) == 0 )
return *(*UserIterator);
}
throw Exception("not find this user");
}
void BindSock(SOCKET sock)
{
sockaddr_in sin;
sin.sin_addr.S_un.S_addr = INADDR_ANY;
sin.sin_family = AF_INET;
sin.sin_port = 0;
if (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0)
throw Exception("bind error");
}
void ConnectToServer(SOCKET sock,char *username, char *serverip)
{
sockaddr_in remote;
remote.sin_addr.S_un.S_addr = inet_addr(serverip);
remote.sin_family = AF_INET;
remote.sin_port = htons(SERVER_PORT);
stMessage sendbuf;
sendbuf.iMessageType = LOGIN;
strncpy(sendbuf.message.loginmember.userName, username, 10);
sendto(sock, (const char*)&sendbuf, sizeof(sendbuf), 0, (const sockaddr*)&remote,sizeof(remote));
int usercount;
int fromlen = sizeof(remote);
int iread = recvfrom(sock, (char *)&usercount, sizeof(int), 0, (sockaddr *)&remote, &fromlen);
if(iread<=0)
{
throw Exception("Login error\n");
}
// 鐧誨綍鍒版湇鍔$鍚庯紝鎺ユ敹鏈嶅姟绔彂鏉ョ殑宸茬粡鐧誨綍鐨勭敤鎴風殑淇℃伅
cout<<"Have "<<usercount<<" users logined server:"<<endl;
for(int i = 0;i<usercount;i++)
{
stUserListNode *node = new stUserListNode;
recvfrom(sock, (char*)node, sizeof(stUserListNode), 0, (sockaddr *)&remote, &fromlen);
ClientList.push_back(node);
cout<<"Username:"<<node->userName<<endl;
in_addr tmp;
tmp.S_un.S_addr = htonl(node->ip);
cout<<"UserIP:"<<inet_ntoa(tmp)<<endl;
cout<<"UserPort:"<<node->port<<endl;
cout<<""<<endl;
}
}
void OutputUsage()
{
cout<<"You can input you command:\n"
<<"Command Type:\"send\",\"exit\",\"getu\"\n"
<<"Example : send Username Message\n"
<<" exit\n"
<<" getu\n"
<<endl;
}
/* 榪欐槸涓昏鐨勫嚱鏁幫細鍙戦佷竴涓秷鎭粰鏌愪釜鐢ㄦ埛(C)
*嫻佺▼錛氱洿鎺ュ悜鏌愪釜鐢ㄦ埛鐨勫緗慖P鍙戦佹秷鎭紝濡傛灉姝ゅ墠娌℃湁鑱旂郴榪?br> * 閭d箞姝ゆ秷鎭皢鏃犳硶鍙戦侊紝鍙戦佺絳夊緟瓚呮椂銆?br> * 瓚呮椂鍚庯紝鍙戦佺灝嗗彂閫佷竴涓姹備俊鎭埌鏈嶅姟绔紝
* 瑕佹眰鏈嶅姟绔彂閫佺粰瀹㈡埛C涓涓姹傦紝璇鋒眰C緇欐湰鏈哄彂閫佹墦媧炴秷鎭?br> * 浠ヤ笂嫻佺▼灝嗛噸澶峂AXRETRY嬈?br> */
bool SendMessageTo(char *UserName, char *Message)
{
char realmessage[256];
unsigned int UserIP;
unsigned short UserPort;
bool FindUser = false;
for(UserList::iterator UserIterator=ClientList.begin();
UserIterator!=ClientList.end();
++UserIterator)
{
if( strcmp( ((*UserIterator)->userName), UserName) == 0 )
{
UserIP = (*UserIterator)->ip;
UserPort = (*UserIterator)->port;
FindUser = true;
}
}
if(!FindUser)
return false;
strcpy(realmessage, Message);
for(int i=0;i<MAXRETRY;i++)
{
RecvedACK = false;
sockaddr_in remote;
remote.sin_addr.S_un.S_addr = htonl(UserIP);
remote.sin_family = AF_INET;
remote.sin_port = htons(UserPort);
stP2PMessage MessageHead;
MessageHead.iMessageType = P2PMESSAGE;
MessageHead.iStringLen = (int)strlen(realmessage)+1;
int isend = sendto(PrimaryUDP, (const char *)&MessageHead, sizeof(MessageHead), 0, (const sockaddr*)&remote, sizeof(remote));
isend = sendto(PrimaryUDP, (const char *)&realmessage, MessageHead.iStringLen, 0, (const sockaddr*)&remote, sizeof(remote));
// 絳夊緟鎺ユ敹綰跨▼灝嗘鏍囪淇敼
for(int j=0;j<10;j++)
{
if(RecvedACK)
return true;
else
Sleep(300);
}
// 娌℃湁鎺ユ敹鍒扮洰鏍囦富鏈虹殑鍥炲簲錛岃涓虹洰鏍囦富鏈虹殑绔彛鏄犲皠娌℃湁
// 鎵撳紑錛岄偅涔堝彂閫佽姹備俊鎭粰鏈嶅姟鍣紝瑕佹湇鍔″櫒鍛婅瘔鐩爣涓繪満
// 鎵撳紑鏄犲皠绔彛錛圲DP鎵撴礊錛?br> sockaddr_in server;
server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT);
stMessage transMessage;
transMessage.iMessageType = P2PTRANS;
strcpy(transMessage.message.translatemessage.userName, UserName);
sendto(PrimaryUDP, (const char*)&transMessage, sizeof(transMessage), 0, (const sockaddr*)&server, sizeof(server));
Sleep(100);// 絳夊緟瀵規柟鍏堝彂閫佷俊鎭?br> }
return false;
}
// 瑙f瀽鍛戒護錛屾殏鏃跺彧鏈塭xit鍜宻end鍛戒護
// 鏂板getu鍛戒護錛岃幏鍙栧綋鍓嶆湇鍔″櫒鐨勬墍鏈夌敤鎴?br>void ParseCommand(char * CommandLine)
{
if(strlen(CommandLine)<4)
return;
char Command[10];
strncpy(Command, CommandLine, 4);
Command[4]='\0';
if(strcmp(Command,"exit")==0)
{
stMessage sendbuf;
sendbuf.iMessageType = LOGOUT;
strncpy(sendbuf.message.logoutmember.userName, UserName, 10);
sockaddr_in server;
server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT);
sendto(PrimaryUDP,(const char*)&sendbuf, sizeof(sendbuf), 0, (const sockaddr *)&server, sizeof(server));
shutdown(PrimaryUDP, 2);
closesocket(PrimaryUDP);
exit(0);
}
else if(strcmp(Command,"send")==0)
{
char sendname[20];
char message[COMMANDMAXC];
int i;
for(i=5;;i++)
{
if(CommandLine[i]!=' ')
sendname[i-5]=CommandLine[i];
else
{
sendname[i-5]='\0';
break;
}
}
strcpy(message, &(CommandLine[i+1]));
if(SendMessageTo(sendname, message))
printf("Send OK!\n");
else
printf("Send Failure!\n");
}
else if(strcmp(Command,"getu")==0)
{
int command = GETALLUSER;
sockaddr_in server;
server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT);
sendto(PrimaryUDP,(const char*)&command, sizeof(command), 0, (const sockaddr *)&server, sizeof(server));
}
}
// 鎺ュ彈娑堟伅綰跨▼
DWORD WINAPI RecvThreadProc(LPVOID lpParameter)
{
sockaddr_in remote;
int sinlen = sizeof(remote);
stP2PMessage recvbuf;
for(;;)
{
int iread = recvfrom(PrimaryUDP, (char *)&recvbuf, sizeof(recvbuf), 0, (sockaddr *)&remote, &sinlen);
if(iread<=0)
{
printf("recv error\n");
continue;
}
switch(recvbuf.iMessageType)
{
case P2PMESSAGE:
{
// 鎺ユ敹鍒癙2P鐨勬秷鎭?br> char *comemessage= new char[recvbuf.iStringLen];
int iread1 = recvfrom(PrimaryUDP, comemessage, 256, 0, (sockaddr *)&remote, &sinlen);
comemessage[iread1-1] = '\0';
if(iread1<=0)
throw Exception("Recv Message Error\n");
else
{
printf("Recv a Message:%s\n",comemessage);
stP2PMessage sendbuf;
sendbuf.iMessageType = P2PMESSAGEACK;
sendto(PrimaryUDP, (const char*)&sendbuf, sizeof(sendbuf), 0, (const sockaddr*)&remote, sizeof(remote));
}
delete []comemessage;
break;
}
case P2PSOMEONEWANTTOCALLYOU:
{
// 鎺ユ敹鍒版墦媧炲懡浠わ紝鍚戞寚瀹氱殑IP鍦板潃鎵撴礊
printf("Recv p2someonewanttocallyou data\n");
sockaddr_in remote;
remote.sin_addr.S_un.S_addr = htonl(recvbuf.iStringLen);
remote.sin_family = AF_INET;
remote.sin_port = htons(recvbuf.Port);
// UDP hole punching
stP2PMessage message;
message.iMessageType = P2PTRASH;
sendto(PrimaryUDP, (const char *)&message, sizeof(message), 0, (const sockaddr*)&remote, sizeof(remote));
break;
}
case P2PMESSAGEACK:
{
// 鍙戦佹秷鎭殑搴旂瓟
RecvedACK = true;
break;
}
case P2PTRASH:
{
// 瀵規柟鍙戦佺殑鎵撴礊娑堟伅錛屽拷鐣ユ帀銆?br> //do nothing ...
printf("Recv p2ptrash data\n");
break;
}
case GETALLUSER:
{
int usercount;
int fromlen = sizeof(remote);
int iread = recvfrom(PrimaryUDP, (char *)&usercount, sizeof(int), 0, (sockaddr *)&remote, &fromlen);
if(iread<=0)
{
throw Exception("Login error\n");
}
ClientList.clear();
cout<<"Have "<<usercount<<" users logined server:"<<endl;
for(int i = 0;i<usercount;i++)
{
stUserListNode *node = new stUserListNode;
recvfrom(PrimaryUDP, (char*)node, sizeof(stUserListNode), 0, (sockaddr *)&remote, &fromlen);
ClientList.push_back(node);
cout<<"Username:"<<node->userName<<endl;
in_addr tmp;
tmp.S_un.S_addr = htonl(node->ip);
cout<<"UserIP:"<<inet_ntoa(tmp)<<endl;
cout<<"UserPort:"<<node->port<<endl;
cout<<""<<endl;
}
break;
}
}
}
}
int main(int argc, char* argv[])
{
try
{
InitWinSock();
PrimaryUDP = mksock(SOCK_DGRAM);
BindSock(PrimaryUDP);
cout<<"Please input server ip:";
cin>>ServerIP;
cout<<"Please input your name:";
cin>>UserName;
ConnectToServer(PrimaryUDP, UserName, ServerIP);
HANDLE threadhandle = CreateThread(NULL, 0, RecvThreadProc, NULL, NULL, NULL);
CloseHandle(threadhandle);
OutputUsage();
for(;;)
{
char Command[COMMANDMAXC];
gets(Command);
ParseCommand(Command);
}
}
catch(Exception &e)
{
printf(e.GetMessage());
return 1;
}
return 0;
}
/* 寮傚父綾?br> *
* 鏂囦歡鍚嶏細Exception.h
*
* 鏃ユ湡錛?004.5.5
*
* 浣滆咃細shootingstars(zhouhuis22@sina.com)
*/
#ifndef __HZH_Exception__
#define __HZH_Exception__
#define EXCEPTION_MESSAGE_MAXLEN 256
#include "string.h"
class Exception
{
private:
char m_ExceptionMessage[EXCEPTION_MESSAGE_MAXLEN];
public:
Exception(char *msg)
{
strncpy(m_ExceptionMessage, msg, EXCEPTION_MESSAGE_MAXLEN);
}
char *GetMessage()
{
return m_ExceptionMessage;
}
};
#endif
/* P2P 紼嬪簭浼犺緭鍗忚
*
* 鏃ユ湡錛?004-5-21
*
* 浣滆咃細shootingstars(zhouhuis22@sina.com)
*
*/
#pragma once
#include <list>
// 瀹氫箟iMessageType鐨勫?br>#define LOGIN 1
#define LOGOUT 2
#define P2PTRANS 3
#define GETALLUSER 4
// 鏈嶅姟鍣ㄧ鍙?br>#define SERVER_PORT 2280
// Client鐧誨綍鏃跺悜鏈嶅姟鍣ㄥ彂閫佺殑娑堟伅
struct stLoginMessage
{
char userName[10];
char password[10];
};
// Client娉ㄩ攢鏃跺彂閫佺殑娑堟伅
struct stLogoutMessage
{
char userName[10];
};
// Client鍚戞湇鍔″櫒璇鋒眰鍙﹀涓涓狢lient(userName)鍚戣嚜宸辨柟鍚戝彂閫乁DP鎵撴礊娑堟伅
struct stP2PTranslate
{
char userName[10];
};
// Client鍚戞湇鍔″櫒鍙戦佺殑娑堟伅鏍煎紡
struct stMessage
{
int iMessageType;
union _message
{
stLoginMessage loginmember;
stLogoutMessage logoutmember;
stP2PTranslate translatemessage;
}message;
};
// 瀹㈡埛鑺傜偣淇℃伅
struct stUserListNode
{
char userName[10];
unsigned int ip;
unsigned short port;
};
// Server鍚慍lient鍙戦佺殑娑堟伅
struct stServerToClient
{
int iMessageType;
union _message
{
stUserListNode user;
}message;
};
//======================================
// 涓嬮潰鐨勫崗璁敤浜庡鎴風涔嬮棿鐨勯氫俊
//======================================
#define P2PMESSAGE 100 // 鍙戦佹秷鎭?br>#define P2PMESSAGEACK 101 // 鏀跺埌娑堟伅鐨勫簲絳?br>#define P2PSOMEONEWANTTOCALLYOU 102 // 鏈嶅姟鍣ㄥ悜瀹㈡埛绔彂閫佺殑娑堟伅
// 甯屾湜姝ゅ鎴風鍙戦佷竴涓猆DP鎵撴礊鍖?br>#define P2PTRASH 103 // 瀹㈡埛绔彂閫佺殑鎵撴礊鍖咃紝鎺ユ敹绔簲璇ュ拷鐣ユ娑堟伅
// 瀹㈡埛绔箣闂村彂閫佹秷鎭牸寮?br>struct stP2PMessage
{
int iMessageType;
int iStringLen; // or IP address
unsigned short Port;
};
using namespace std;
typedef list<stUserListNode *> UserList;
宸ョ▼涓嬭澆鍦板潃:http://www.ppcn.net/upload/2004_05/04052509317298.rar