• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 94, comments - 250, trackbacks - 0, articles - 0
              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            Nebula3的網(wǎng)絡(luò)子系統(tǒng)提供了基于TCP協(xié)議的簡(jiǎn)單C/S通信模式. 它并沒有打算做成大廳,會(huì)話管理還有玩家數(shù)據(jù)同步的面向游戲的高級(jí)通信. 這些以后會(huì)在更高層的Nebula3子系統(tǒng)中出現(xiàn).

            使用IP地址

              一個(gè)IpAddress對(duì)象通過主機(jī)名字或TCP/IP地址加一個(gè)端口號(hào)定義了一個(gè)通信端點(diǎn). IpAddress對(duì)象可以通過多數(shù)方式建立:

            1: // 從 TCP/IP 地址和端口號(hào):

            2: IpAddress ipAddr("192.168.0.2",1234);

            3:

            4: // 從主機(jī)名和端口號(hào):

            5: IpAddress ipAddr("www.radonlabs.de",1234);

            6:

            7: // 從本機(jī)(127.0.0.1) 和端口號(hào):

            8: IpAddress ipAddr("localhost",1234);

            9:

            10: // 從"any" 地址 (0.0.0.0) 和端口號(hào):

            11: IpAddress ipAddr("any",1234);

            12:

            13: // 從廣播地址 (255.255.255.255) 和端口號(hào):

            14: IpAddress ipAddr("broadcast",1234);

            15:

            16: // 從主機(jī)的第一個(gè)合法網(wǎng)絡(luò)適配器的地址和端口號(hào)

            17: IpAddress ipAddr("self",1234);

            18:

            19: // 從主機(jī)的第一個(gè)連接到互聯(lián)網(wǎng)的網(wǎng)絡(luò)適配器的地址和端口號(hào):

            20: IpAddress ipAddr("insetself",1234);

            21:

            22: // 從一個(gè)定義了主機(jī)名的URI和端口號(hào):

            23: IpAddress ipAddr(IO::URI("http://www.radonlabs.de:2100"));

              一個(gè)IpAddress對(duì)象可以用于從主機(jī)名查找TCP/IP地址:

            1: IpAddress ipAddr("www.radonlabs.de",0);

            2: String numericalAddr = ipAddr.GetHostAddr();

            建立一個(gè)客戶端/服務(wù)器系統(tǒng)

              網(wǎng)絡(luò)子系統(tǒng)用TcpServer和TcpClient類實(shí)現(xiàn)了一個(gè)易用的基于TCP協(xié)議的C/S系統(tǒng). 一個(gè)TcpServer可以為任意數(shù)量的TcpClient服務(wù).

              建立一個(gè)服務(wù)器可以這么做:

            1: using namespace Net;

            2:

            3: Ptr<TcpServer> tcpServer = TcpServer::Create();

            4: tcpServer->SetAddress(IpAddress("any",2352));

            5: if(tcpServer->Open())

            6: {

            7: // TcpServer successfully opened

            8: }

              這樣會(huì)建立一個(gè)在2352端口監(jiān)聽客戶端連接請(qǐng)求的服務(wù)器.

              為了跟TcpServer通信, 需要在客戶端建立一個(gè)TcpClient對(duì)象:

            1: using namespace Net;

            2:

            3: Ptr<TcpClient> tcpClient = TcpClient::Create();

            4: tcpClient->SetBlocking(false);

            5: tcpClient->SetAddress(IpAddress("localhost",2352));

            6: TcpClient::Result res = tcpClient->Connect();

              這里假設(shè)服務(wù)端和客戶端運(yùn)行在同一臺(tái)機(jī)器上(因?yàn)榭蛻舳诉B接到了”localhost”).

              像上面那樣非阻塞的情況, Connect()方法不是返回TcpClient::Success(這意味著連接建立好了)就是TcpClient::Connecting, 如果這樣的話, 應(yīng)用程序需要繼續(xù)調(diào)用Connect()方法. 如果連接錯(cuò)誤, 會(huì)返回一個(gè)TcpClient::Error的返回值.

              如果是阻塞的, Connect()方法直到連接建立(結(jié)果是TcpClient::Success)或發(fā)生錯(cuò)誤才會(huì)返回.

              注意:一個(gè)交互式應(yīng)用程序不應(yīng)該在網(wǎng)絡(luò)通信時(shí)阻塞, 而應(yīng)不斷地為用戶提供反饋.

              一旦連接建立, 服務(wù)端會(huì)為每個(gè)客戶機(jī)建立一個(gè)TcpClientConnection對(duì)象. TcpClientConnection在服務(wù)器上表示客戶機(jī), 并且負(fù)責(zé)從客戶機(jī)收發(fā)數(shù)據(jù).

              要進(jìn)行接收和發(fā)送數(shù)據(jù)的話, 需使用IO::Stream對(duì)象. 在通信流上連接IO::StreamReader和IO::StreamWriter對(duì)象后, 從流中編碼和解碼數(shù)據(jù)是一件非常容易的事情.

              注意:發(fā)送數(shù)據(jù)并不是即時(shí)的, 而是在Send()方法被調(diào)用之前會(huì)一直保存在發(fā)送流當(dāng)中.

              要客戶端給服務(wù)器發(fā)送一些文本數(shù)據(jù)話, 只要從發(fā)送流獲取一個(gè)指針, 向其中寫入數(shù)據(jù)后調(diào)用Send()方法就可以了:

            1: using namespace Net;

            2: using namespace IO;

            3:

            4: // obtain pointer to client's send stream and attach a TextWriter

            5: const Ptr<Stream>& sendStream = tcpClient->GetSendStream();

            6: Ptr<TextWriter> textWriter = TextWriter::Create();

            7: textWriter->SetStream(sendStream);

            8: textWriter->Open())

            9: textWriter->WriteString("Hello Server");

            10: textWriter->Close();

            11:

            12: // send off the data to the server

            13: if(this->tcpClient->Send())

            14: {

            15: // data has been sent

            16: }

              在服務(wù)器端接收客戶端數(shù)據(jù), 應(yīng)用程序需要要頻繁地(每幀一次)緩存帶有客戶羰數(shù)據(jù)的TcpClientConnection. 可能不只一個(gè)TcpClientConnection在等待處理, 因此處理循環(huán)應(yīng)該像這樣:

            1: // get array of client connections which received data since the last time

            2: Array<Ptr<TcpClientConnection>> recvConns = tcpServer->Recv();

            3: IndexT i;

            4: for(i =0; i < recvConns.Size(); i++)

            5: {

            6: // get receive stream from current connection, attach a text reader and read content

            7:      Ptr<TextReader> textReader = TextReader::Create();

            8:      textReader->SetStream(recvConns[i]->GetRecvStream());

            9:      textReader->Open();

            10:      String str = textReader->ReadString();

            11:      textReader->Close();

            12:

            13: // process received string and send response back to client

            14: // create a TextWriter and attach it to the send stream of the client connection

            15:      Ptr<TextWriter> textWriter = TextWriter::Create();

            16:      textWriter->SetStream(recvConns[i]->GetSendStream());

            17:      textWriter->Open();

            18:      textWriter->WriteString("Hello Client");

            19:      textWriter->Close();

            20:

            21: // finally send the response back to the client

            22:      recvConns[i]->Send();

            23: }

              在客戶端獲得服務(wù)器的應(yīng)答, 調(diào)用TcpClient::Recv()方法會(huì)在數(shù)據(jù)到達(dá)之前一直阻塞(在阻塞模式下), 或者立即返回(在非阻塞模式下), 并在有服務(wù)器數(shù)據(jù)時(shí)返回true:

            1: // check if data is available from the server

            2: if(tcpClient->Recv())

            3: {

            4: // yep, data is available, get the recv stream and read the data from it

            5: const Ptr<Stream>& recvStream = tcpClient->GetRecvStream();

            6:      Ptr<TextReader> textReader = TextReader::Create();

            7:      textReader->SetStream(recvStream);

            8:      textReader->Open();

            9:      String responseString = textReader->ReadString();

            10:      n_printf("The server said: %s\n", responseString.AsCharPtr());

            11:      textReader->Close();

            12: }

              客戶端也應(yīng)該通過調(diào)用IsConnected()訪求檢查連接是否有效. 如果因?yàn)槟承┰蚴惯B接斷開, 這個(gè)方法會(huì)返回false.

              注意:

            TcpServer和TcpClient并沒有為能夠跟不相關(guān)的客戶端和服務(wù)器端而實(shí)現(xiàn)一個(gè)潛在的通信協(xié)議(例如, 一個(gè)TcpServer可以跟標(biāo)準(zhǔn)的Web瀏覽器客戶端一起工作, 還有一個(gè)TcpClient類可以跟一個(gè)標(biāo)準(zhǔn)的HTTP服務(wù)器通信).

              現(xiàn)實(shí)世界的情況是, 一個(gè)應(yīng)用程序應(yīng)該實(shí)現(xiàn)自己的健壯的通信協(xié)議, 它至少會(huì)編碼負(fù)載數(shù)據(jù)的長(zhǎng)度. 如果負(fù)載比最大包大小還要大, 數(shù)據(jù)會(huì)以多個(gè)包發(fā)送并在客戶端接收. 客戶端應(yīng)該把數(shù)據(jù)解碼成一個(gè)完整的消息, 否則需要等待消息的數(shù)據(jù)接收完畢.

            字節(jié)次序問題

              服務(wù)器和客戶端可能運(yùn)行在不同字節(jié)次序的的CPU上. 如果二進(jìn)制數(shù)據(jù)通過網(wǎng)絡(luò)發(fā)送, 數(shù)據(jù)必需轉(zhuǎn)換成兩個(gè)客戶端都一致的”網(wǎng)絡(luò)字節(jié)順序”. Nebula3在IO::BinaryReader和IO::BinaryWriter類中提供字節(jié)順序的自動(dòng)轉(zhuǎn)換. 只需要簡(jiǎn)單地調(diào)用下面的方法在網(wǎng)絡(luò)通信流上讀寫就可以了:

            1: binaryReader->SetStreamByteOrder(System::ByteOrder::Network);

            2: binaryWriter->SetStreamByteOrder(System::ByteOrder::Network);

            Socket

              網(wǎng)絡(luò)子系統(tǒng)提供了一個(gè)把傳統(tǒng)socket函數(shù)包裝成C++接口的Socket類. 一般情況下應(yīng)用程序不直接使用Socket類, 而是使用更高級(jí)的像TcpServer這樣的類. 但也不是不可能在有的時(shí)候直接使用socket函數(shù)比Socket類更方便.


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            精品久久久噜噜噜久久久| 国产精品久久久久久久| 久久91综合国产91久久精品| 久久久久成人精品无码中文字幕 | 色青青草原桃花久久综合| 久久人妻AV中文字幕| 久久精品亚洲一区二区三区浴池| 久久香蕉国产线看观看精品yw| 精品久久久久久久久久久久久久久| 99久久精品国产一区二区| 狠狠精品久久久无码中文字幕| 中文字幕久久精品 | 亚洲日本va中文字幕久久| 狠狠久久亚洲欧美专区| 亚洲国产日韩欧美综合久久| 国内精品人妻无码久久久影院| 日韩十八禁一区二区久久| 色8久久人人97超碰香蕉987| 亚洲精品高清久久| 久久91综合国产91久久精品 | 欧美国产成人久久精品| 内射无码专区久久亚洲| 青青热久久综合网伊人| 久久国产精品-久久精品| 久久久久久久久久久久久久| 久久久精品波多野结衣| 久久久WWW成人| 91精品国产综合久久香蕉| 无码国产69精品久久久久网站| 中文国产成人精品久久不卡| 国产精品热久久无码av| 性做久久久久久久久久久| 久久综合丝袜日本网| 色综合久久久久综合体桃花网| 亚洲国产精品一区二区三区久久 | 亚洲欧美精品伊人久久| 久久精品一区二区三区不卡| 香蕉久久夜色精品升级完成| 久久无码AV中文出轨人妻| 久久强奷乱码老熟女网站 | 99久久精品费精品国产一区二区|