C++服務器端+Android客戶端的網絡通信

http://blog.sina.com.cn/s/blog_4e928b170100yg9c.html


今天晚上11點半,在學校斷網後的十分鐘,我終於實現了C++服務器端與Android客戶端的通信。本來很簡單的一件事,卻因爲Android Socket線程阻塞的問題弄了我兩天。

好了不多說,直接進入主題:

 

C++ 服務器端:

C++進行網絡編程有很多方式,比如可以使用winSockwinInt,或者使用MFC的封裝類CSocket等等。這裏我使用的是比較簡單的CSocket類來實現。

這裏先簡單說說使用CSocket類來建立服務器端的過程:

 

C++服務器端+Android客戶端的網絡通信

上圖是C++服務器端與Android客戶端通信的流程圖。

 

看到上面的流程圖,C++程序員應該感到高興,這不就是CSocket客戶端的變體嘛。服務器端完全沒變化,這先不說,Android客戶端連connet動作都省下來了。

這……是不是寫錯了?

沒錯,確實連connet這個步驟都省了。當然,沒有connect只不過是因爲這個connect的動作直接被封裝到了Android Socketnew操作裏而已。不然,服務器端怎麼可能知道你這個狡猾的客戶端會不會三更半夜的來敲門,說要提供服務啊。哈哈。

注:在Android Socket的構造函數中有多種形式,並不是每一種形式都必須在構造時就連接到服務器。讀者可以自己閱讀Android的開發文檔,你會發現Socket也有個名爲Connect的成員函數。

 

好了,有了基本的操作流程後,寫起代碼來就容易多了。

 

觀察流程圖中C++服務器端的構造過程可以知道,服務器端的構造大致分爲三大步驟:

1、創建用於偵聽的socket套接字sevSock並開啓偵聽;

2、創建用於接收/發送信息的socket套接字reveiceSoc,創建後“綁定”到偵聽套接字;

3、reveiceSoc套接字接收/發送信息。

 

這幾個步驟對於C++程序員來說已經是滾瓜爛熟了。

我也不多說,直接動手更見效。

(開發環境:VS 2008

第一步:創建一個新MFC應用程序項目,這裏名爲AndroidSocket,應用程序類型爲“基於對話框”就可以了。並且在創建過程的嚮導中的高級功能的選項中選中windows套接字。

第二步:添加用於偵聽的socket套接字。爲項目添加一個MFC類用於偵聽客戶端的連接,並令該類的基類爲CSocket。本例中該類的類名爲CAndroidSoc

第三步:添加用於接收/發送信息的socket套接字。再爲項目添加一個MFC類用於接收/發送信息,該類也要繼承於CSocket。本例中該類的類名爲CRevSocket

第四步:爲對話框類添加成員變量CAndroidSoc m_androidSoc,,並在OnInitDialog()函數中添加如下代碼:

m_androidSoc.Create(8005,SOCK_STREAM);//創建偵聽套接字

m_androidSoc.Listen();//開啓偵聽

第五步:重寫“偵聽”套接字CAndroidSoc的虛函數OnAccept()。並在OnAccept的實現中添加如下代碼:

CRevSocket* pRveSocket=new CRevSocket(); //創建用於接收/發送信息的套接字

this->Accept(*pRveSocket);//讓“偵聽”套接字綁定“接收/發送信息”的套接字

第六步:重寫“接收/發送信息”套接字CRevSocket的虛函數OnReceive()。並在該函數的實現中添加如下代碼:

wchar_t* wch=new wchar_t[1024*4]; //申請緩衝區

memset(wch,0,1024*4); //清空緩衝區

this->Receive(wch,1024*4); //接收客戶端發送過來的信息

AfxMessageBox(wch); //顯示信息(這裏只不過用於測試用戶發送過來的信息而已)

Delete wch; //釋放空間

 

實現了以上六個步驟,服務器端就算是建好了。當然,上面只是簡單的建立了服務器端接收客戶端發送過來的信息的而已。至於服務器端向客戶端發送信息的步驟也非常簡單,我就不多說了。百度一搜就一大堆。

 

接下來就講講Android客戶端的創建:

如果讀者對Android編程有一些基礎的話,看到上面的客戶端建立的流程圖,心中肯定會暗喜:oh,my lady gaga.這花不了哥(姐)10分鐘。可是,十分鐘過去了,二十分鐘過去了,甚至到了飢腸轆轆,這個手機還是不能成功的發送一條信息到服務器去。檢測了代碼十幾遍,沒錯啊。也是按照圖上的流程來做的,不會流程圖有問題吧?

哥(姐),恭喜你,你懷疑對了。學習就是需要懷疑,不然怎麼又突破。我記得我小學老師曾這麼教訓我們這些每次作業都抄書上答案的同學說:“讀書不可盡信書,盡信書,不如無書!”。這話啊,當頭棒喝,我們當即就遵循了“無書”的真理。哈哈,開個玩笑。

不過你想得確實沒錯。確實是流程圖有問題。不過這個問題並不是像少了Connect操作這麼明顯(當然,這個步驟本來就不需要)。而是進入了線程的問題。

大家應該知道吧。使用AndroidSocket類來開發網絡通信應用,意味着你用的是TCP協議進行網絡通信。而TCP協議是一種面向連接的通信方式。何爲面向連接,簡單的說就是你的客戶機必須先和服務器進行了連接,連接了還不行,還要一直佔用一條通信電路(當然,這個概念並不是佔用了一條電線這麼簡單),直到你主動或者被動地與服務器斷開連接。而在整個連接過程中,你的程序就一直在等待,這就是阻塞了。那麼程序在等待什麼?等待愛情?當然不,它是在等待服務器的響應。

其實,對於這個AndroidSocket開發,剛開始時我也是很鬱悶。在編寫一個簡單的Scoket通信應用時,我參考了不少書,並且也按書上寫的照打了一遍,可是結果不是直接崩潰就是根本通不了信,服務器連個連接的請求都沒有接收到。

好吧。既然都已經說了這麼多,是應該告訴解決方法了。其實方法也是很簡單,就是新建一個線程,將Socket的操作放到該線程上。

解決方法:新建線程,代碼如下:

//OnCreate函數中添加

Try //創建線程,並通過Socket與服務器建立連接

{

Thread thread=new Thread(new Runnable(){

 

@Override

public void run() {

// TODO Auto-generated method stub

try{

s=new Socket("192.168.0.105",8005);

outputStream=s.getOutputStream();

}

catch(Exception e){

e.printStackTrace();

}

}

});

thread.start();

}

catch(Exception e)

{

e.printStackTrace();

}

 

//OnCreate函數中添加按鈕響應函數,

//實現用戶按下按鈕,就想服務器端發送“SUCCEEDED!”信息

ITButton=(Button)findViewById(R.id.BuildingIB);

ITButton.setOnClickListener(new OnClickListener()

{

 

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

byte[] buffer=new byte[4*1024];

String strbuffer="succeeded!";

buffer=strbuffer.getBytes();

try {

 

outputStream.write(buffer);

catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

});

 

好了!Android客戶端的編寫也算是完成了。雖然不詳細,不過大家應該看得懂。


發佈了45 篇原創文章 · 獲贊 6 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章