




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
1、Unity3D之C#使用 Socket 與 HTTP 連接服務(wù)器傳輸數(shù)據(jù)包(2013-04-29 11:13:17):分類:Unity3dit,代碼:using UnityEngine;using System.Collections; using System;using System.Threading; using System.Text; using System.Net;using System.Net.Sockets;using System.Collections.Generic; using System.IO;using System.Runtime.eropServi; u
2、sing System.Runtime.Serialization;using System.Runtime.Serialization.Formatters.Binary;From:htt/android-497-1.html(只為本人學(xué)習(xí),感謝本文作者) 1.SocketSocket 不要寫在上,如果寫在上場景一旦切換,那么這條會被掉, Socket 會斷開連接。場景切換完畢后需要重新在與服務(wù)器建立 Socket 連接,這樣會很麻 煩。所以需要把 Socket 寫在一個單例的類中,不用繼承 MonoBehaviour。這個例子我模擬一下,主角在中移動,時時向服務(wù)端發(fā)送當(dāng)前坐標(biāo),當(dāng)服務(wù)器返回
3、同步坐標(biāo)時角色開始同步服務(wù)端新角色坐標(biāo)。Socket 在發(fā)送消息的時候采用的是字節(jié)數(shù)組,也就是說無論你的數(shù)據(jù)是float short object 都會將這些數(shù)據(jù)類型先轉(zhuǎn)換成 byte ,目前在處理發(fā)送的地方我使用的是數(shù)據(jù)包也就是把(角色坐標(biāo))結(jié)構(gòu)體 object 轉(zhuǎn)換成 byte發(fā)送,這就牽扯一個問題,如何把結(jié)構(gòu)體轉(zhuǎn)成字節(jié)數(shù)組,如何把字節(jié)數(shù)組回轉(zhuǎn)成結(jié)構(gòu)體。請大家接續(xù)閱讀,就在后面,哇咔咔。直接上代碼JFSocket.cs 該單例類不要綁定在任何對象上/public class JFSocket/Socket 客戶端對象private Socket cntSocket;/JFPackage.W
4、orldPackage 是我封裝的結(jié)構(gòu)體,/在與服務(wù)器交互的時候會傳遞這個結(jié)構(gòu)體/當(dāng)客戶端接到到服務(wù)器返回的數(shù)據(jù)包時,我把結(jié)構(gòu)體 add public List worldpackage;/單例模式存在鏈表中。private sic JFSockettance;tance()public sic JFSocket Getif (tance = null)tance = new JFSocket();returntance;/單例的構(gòu)造函數(shù) JFSocket()/創(chuàng)建 Socket 對象,這里連接類型是 TCPcntSocket = new Socket(AddressFamily.erNetw
5、ork,SocketType.Stre/服務(wù)器 IP 地址rotocolType.Tcp);IPAddress ipAddress = IPAddress.Parse (00);/服務(wù)器端口IPEndPoipEndpo= new IPEndPo(ipAddress, 10060);/這是一個異步的建立連接,當(dāng)連接建立成功時調(diào)用 connectCallback 方法IAsyncResultresult = cntSocket.BeginConnect (ipEndpo,new AsyncCallback(connectCallback),cntSocket);/這里做一個超時的監(jiān)測,當(dāng)連接超過
6、5 秒還沒成功表示超時bool sucs = result.AsyncWaindle.WaitOne( 5000, true );if ( !suc/超時 Closed();s )Debug.Log(connect Time Out);else/與 socket 建立連接成功,開啟線程接受服務(wù)端數(shù)據(jù)。worldpackage = new List();Thread thread = new Thread(new ThreadStart(ReceiveSorket); thread.IsBackground = true;thread.Start();private void connectCa
7、llback(IAsyncResultasyncConnect) Debug.Log(connectSuc;s)private void ReceiveSorket()/在這個線程中接受服務(wù)器返回的數(shù)據(jù) while (true) if(!c)ntSocket.Connected/與服務(wù)器斷開連接跳出循環(huán)Debug.Log(Failed to cntSocket server.);cntSocket.Close();break;try/接受數(shù)據(jù)保存至 bytes 當(dāng)中byte bytes = new byte4096;/Receive 方法中會一直等待服務(wù)端回發(fā)消息/如果沒有回發(fā)會一直在這里等著
8、。i = cntSocket.Receive(bytes); if(i 2) SplitPackage(bytes,0);elseDebug.Log(length is notcatch (Exception e)Debug.Log(Failed to c 2);ntSocket error.+ e);cntSocket.Close();break;private void SplitPackage(byte bytes ,index)/在這里進行拆包,因為一次返回的數(shù)據(jù)包的數(shù)量是不定的/所以需要給數(shù)據(jù)包進行查分。 while(true)/包頭是 2 個字節(jié)byte head = new by
9、te2; headLengthIndex = index + 2;/把數(shù)據(jù)包的前兩個字節(jié)拷貝出來 Array.Copy(bytes,index,head,0,2);/計算包頭的長度short length = BitConverter.To16(head,0);/當(dāng)包頭的長度大于 0 那么需要依次把相同長度的 byte 數(shù)組拷貝出來if(length 0)byte data = new byength;/拷貝出這個包的全部字節(jié)數(shù)Array Copy(bytes headLengthIndex data 0 length);/把數(shù)據(jù)包中的字節(jié)數(shù)組強制轉(zhuǎn)換成數(shù)據(jù)包的結(jié)構(gòu)體/BytesToStruc
10、t()方法就是用來轉(zhuǎn)換的/這里需要和的服務(wù)端程序商量,JFPackage.WorldPackage wp = new JFPackage.WorldPackage();wp = (JFPackage.WorldPackage)BytesToStruct(data,wp.GetType();/把每個包的結(jié)構(gòu)體對象添加至鏈表中。 worldpackage.Add(wp);/將索引指向下一個包的包頭index = headLengthIndex + length;else/如果包頭為 0 表示沒有包了,那么跳出循環(huán)break;/向服務(wù)端發(fā)送一條字符串/一般不會發(fā)送字符串應(yīng)該是發(fā)送數(shù)據(jù)包publicb
11、yteif(!c cvoid SendMessage(string str)msg = Encoding.UTF8.GetBytes(str);ntSocket.Connected)ntSocket.Close(); return;try/i = cntSocked(msg);IAsyncResult asyncSend = cntSocket.Begend(msg,0,msg.Length,SocketFlags.None,new AsyncCallback(sendCallback),cntSocket);bool if ( c;sucs = asyncSend.AsyncWaindle.
12、WaitOne( 5000, true );!sucs )ntSocket.Close()Debug.Log(Failed to SendMessage server.);,catchDebug.Log(send message error );/向服務(wù)端發(fā)送數(shù)據(jù)包,也就是一個結(jié)構(gòu)體對象 public void SendMessage(object obj) if(!cntSocket.Connected) cntSocket.Close(); return;try/先得到數(shù)據(jù)包的長度short size = (short)Marshal.SizeOf(obj);/把數(shù)據(jù)包的長度寫入 byte
13、 數(shù)組中byte head = BitConverter.GetBytes(size);/把結(jié)構(gòu)體對象轉(zhuǎn)換成數(shù)據(jù)包,也就是字節(jié)數(shù)組 byte data = StructToBytes(obj);/此時就有了兩個字節(jié)數(shù)組,一個是標(biāo)記數(shù)據(jù)包的長度字節(jié)數(shù)組,一個是數(shù)據(jù)包字節(jié)數(shù)組/同時把這兩個字節(jié)數(shù)組合并成一個字節(jié)數(shù)組byte newByte = new bytehead.Length + data.Length; Array.Copy(head,0,newByte,0,head.Length); Array.Copy(data,0,newByte,head.Length, data.Length);
14、/計算出新的字節(jié)數(shù)組的長度length = Marshal.SizeOf(size) + Marshal.SizeOf(obj);/向服務(wù)端異步發(fā)送這個字節(jié)數(shù)組IAsyncResult asyncSend = cntSocket.Begend (newByte,0,length,SocketFlags.None,new AsyncCallback (sendCallback),cntSocket);/監(jiān)測超時bool sucs = asyncSend.AsyncWaindle.WaitOne( 5000, true ); if ( !sucs )cntSocket.Close();Debug.
15、Log(Time Out !);catch (Exception e)Debug.Log(send message error: + e );/結(jié)構(gòu)體轉(zhuǎn)字節(jié)數(shù)組public byte StructToBytes(object structObj)size = Marshal.SizeOf(structObj);Ptr buffer = Marshal.AllocHGlobal(size); try Marshal.StructureToPtr(structObj,buffer,false); byte bytes = new bytesize; Marshal.Copy(buffer, byt
16、es,0,size); return bytes;finally Marshal.FreeHGlobal(buffer);/字節(jié)數(shù)組轉(zhuǎn)結(jié)構(gòu)體public object BytesToStruct(byte bytes, Type strcutType)size = Marshal.SizeOf(strcutType);Ptr buffer = Marshal.AllocHGlobal(size); try Marshal.Copy(bytes,0,buffer,size);return Marshal.PtrToStructure(buffer, strcutType);finally為了與服
17、務(wù)端達成默契,判斷數(shù)據(jù)包是否完成。需要在數(shù)據(jù)包中定義包頭,包頭一般把兩個數(shù)據(jù)類型 short是這個數(shù)據(jù)包的長度,也就是結(jié)構(gòu)體對象的長度。正如代碼中和 object 合并成一個新的字節(jié)數(shù)組。然后是數(shù)據(jù)包結(jié)構(gòu)體的定義,需要注意如果你在做 IOS 和 Android 的話數(shù)據(jù)包中不要包含數(shù)組,不然在結(jié)構(gòu)體轉(zhuǎn)換 byte 數(shù)組的時候會出錯。Marshal.StructureToPtr () error : Attempting to JIT compile methodJFPackage.cs代碼:usingUnityEngine;usingSystem.Collections;usingSystem
18、.Runtime.eropServi;public class JFPackageMarshal.FreeHGlobal(buffer);private void sendCallback (IAsyncResult asyncSend)/關(guān)閉 Socketpublic void Closed()if(cntSocket != null & cntSocket.Connected) cntSocket.Shutdown(SocketShutdown.Both); cntSocket.Close();cntSocket = null;/結(jié)構(gòu)體序列化System.Serializable/4 字節(jié)
19、對齊和 android 上可以 1 字節(jié)對齊StructLayout(LayoutKind.Sequential,Pack=4)public structWorldPackagepublicbytemEqui;publicbytemAnimationID;publicbytemHP;publicshortmx;publicshortmy;publicshortmz;publicshortmRosx;publicshortmRosy;publicshortmRosz;public WorldPackage(shortx,shorty,shortz, shortrosx,shortrosy,sho
20、rt rosz,byte equi,byteanimationID,byte hp)mx=x;my=y;mz=z;mRosx=rosx;mRosy=rosy;mRosz=rosz;mEqui= equi;mAnimationID = animationID;mHP = hp;中執(zhí)行發(fā)送數(shù)據(jù)包的動作,在 Start 方法中得到 Socket 對象。在代碼:public JFSocket mJFsorket; void Start () mJFsorket =JFSocket.Gettance(); 讓角色發(fā)生移動的時候,調(diào)用該方法向服務(wù)端發(fā)送數(shù)據(jù)。代碼:void SendPlayerWorldM
21、essage() /組成新的結(jié)構(gòu)體對象,包括主角坐標(biāo)旋轉(zhuǎn)等。 Vector3 PlayerTransform = transform.localition; Vector3PlayerRoion = transform.localRoion.eulerAngles; /用 short 的話是 2 字節(jié),為了節(jié)省包的長度。這里乘以 100 避免使用 float 4 字節(jié)。當(dāng)服務(wù)器接受到的時候小數(shù)點向前移動兩位就是真實的 float 數(shù)據(jù) short px =(short)(PlayerTransform.x*100);shortpy=(short)(PlayerTransform.y*100);
22、shortpz=(short)(PlayerTransform.z*100);shortrx=(short)(PlayerRoion.x*100);short ry =(short)(PlayerRoion.y*100);short rz =(short)(PlayerRoion.z*100);byte equi= 1; byte animationID =9;byte hp = 2; JFPackage.WorldPackage wordPackage = newJFPackage.WorldPackage(px,py,pz,rx,ry,rz,equi,animationID,hp); /通
23、過 Socket 發(fā)送結(jié)構(gòu)體對象 mJFsorkedMessage(wordPackage); 接著就是客戶端同步服務(wù)器的數(shù)據(jù),目前是測試階段所以寫的比較簡陋,不過原理都是一樣的。代碼:/上次同步時間 private float mSynchronous; void Update () mSynchronous +=Time.delime; /在 Update 中每 0.5s 的時候同步一次if(mSynchronous 0.5f) count = mJFsorket.worldpackage.Count;/當(dāng)接受到的數(shù)據(jù)包長度大于0 開始同步 if(count 0) /遍歷數(shù)據(jù)包中每個點的坐
24、標(biāo) foreach(JFPackage.WorldPackage wp inmJFsorket.worldpackage) float x = (float)(wp.mx / 100.0f); floaty = (float)(wp.my/100.0f); float z =(float)(wp.mz /100.0f);Debug.Log(x = + x+ y = + y+ z = + z); /同步主角的新坐標(biāo)mPlayer.transform.ition = new Vector3(x,y,z); /清空數(shù)據(jù)包鏈表mJFsorket.worldpackage.Clear(); mSynch
25、ronous = 0; 主角移動的同時,通過 Socket 時時同步坐標(biāo)喔。有沒有感覺這個牛頭人非常帥氣 哈哈哈。對于 Socket 的使用,我相信沒有比 MSDN 更加詳細(xì)的了。 有關(guān) Socket 同步請求異步請求的地方可以參照 MSDN地址給出來了,好好學(xué)習(xí)吧,嘿嘿。 HYPERLINK http:/m/ http:/m/library/.sockets.socket.aspx上述代碼中我使用的是 Thread() 沒有使用協(xié)同任務(wù) StartCoroutine() ,原因是協(xié)同任務(wù)必需要繼承 MonoBehaviour,并且該要綁定在對象身上。問題綁定在對象身上,那么 Socket 肯
26、定會斷開連接,所以我需要用切換場景的時候這個必然會Thread,并且協(xié)同任務(wù)它并不是嚴(yán)格意義上的多線程。2.HTTPHTTP 請求在 Unity 我相信用的會更少一些,因為 HTTP 會比 SOCKET 慢很多,因為它每次請求完都會斷開。廢話不說了,我用 HTTP 請求制作用戶的登錄。用 HTTP 請求直接使用 Unity 自帶的 www 類就可以, 為 HTTP 請求只有登錄才會有,所以我就在中來完成,使用 www 類 和 協(xié)同任務(wù) StartCoroutine()。代碼:using UnityEngine; using System.Collections; usingSystem.Collections.Generic; public class LoginGlobe : MonoBehaviour void Start () /GET請求StartCoroutine(GET(htt/); void Update () v
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 企業(yè)投融資合同樣本
- 企業(yè)單位勞務(wù)分包合同樣本
- 個人投資店鋪合同樣本
- 親人撫養(yǎng)合同標(biāo)準(zhǔn)文本
- 專利轉(zhuǎn)讓標(biāo)準(zhǔn)合同樣本
- 書法采購合同樣本樣本
- 產(chǎn)品開發(fā)協(xié)議合同樣本
- 充電樁驗收合同樣本
- l錄用合同標(biāo)準(zhǔn)文本
- 臨時便道合同標(biāo)準(zhǔn)文本
- 學(xué)前兒童游戲自考復(fù)習(xí)資料考綱
- 兒童抽動癥的診斷與治療
- 《村居》獲獎版 教學(xué)課件
- 無菌技術(shù)操作PPT
- 周版正身圖動作詳解定稿201503剖析
- 第6章工廠布局設(shè)計課件
- 叉車定期檢驗研究分析報告
- 雷達生命探測儀培訓(xùn)-PPT課件
- 光纜和管道的施工規(guī)范標(biāo)準(zhǔn)
- (高清版)建筑工程裂縫防治技術(shù)規(guī)程JGJ_T 317-2014
- 陜西沉積釩礦勘查規(guī)范(1)
評論
0/150
提交評論