簡單設計並開發一個行動通訊程式
網路越來越好,手機之間的互動已經是常態,王者榮耀、微信實時視訊等,已經將多屏互動推到各到各種應用場景。
為了讓大家能清楚地瞭解多屏互動,我將結合例項對移動裝置實時通訊進行研究,並系統性地呈現一些解決方案。
最開始,我嘗試給大家展示如何建立一個最簡單的點對點通訊。
萬事開頭難,先假定一下需求:
區域網內通訊。
寫一個你看我畫的程式。
純客戶端(一開始,我不打算讓伺服器參與)。
下面對需求進行進一步的分析。
需求分析
我做了一個簡單的原型設計,如下圖,其實真正的狀態比這個稍複雜,這裡提供一下 原型連結
需求原型
從原型上看,我們的流程應該是下圖的形式。
流程圖
下面我們進行架構設計與開發選型了。
架構設計
基於前文的需求假定進行簡單設計網路模型,我將目標的網路分拆成3層:
網路模型
對應的開發架構應該是這樣的
開發架構
開發規則
基於實時通訊的高效性,我將底層庫的開發語言選擇了C++,協議格式選擇為二進位制,網路層協議選擇UDP(後面會有切換TCP的選擇)。
通訊協議埠我選擇12000.
欄位 | 註解 |
---|---|
底層庫開發語言 | C++ |
協議格式 | 二進位制 |
網路層協議 | UDP |
通訊埠 | 12000 |
下面我將開始搭建底層庫(寫到這裡還是一行程式碼都沒寫,不過現在是國慶節,既然有時間那就開始搞吧)。
底層庫搭建
建立工程
工程目錄如下
我設計的busi標頭檔案,給上層呼叫的。(詳細的見 github)
#ifndef hello_busi_hpp
#define hello_busi_hpp
#include <stdio.h>
namespace hello{
class BusiInterface{
public:
virtual int onInit(int myIp, int myPort);
virtual int onLink(int srcIndex, int srcIp, int srcPort, const char* srcName, int nameSize);
virtual int onConfirm(int srcIndex, const char* srcName, int nameSize);
virtual int onCancel(int srcIndex);
virtual int onMsg(int srcIndex, const char* msg, int size);
};
class Busi{
public:
Busi();
virtual ~Busi();
virtual int init(BusiInterface* itf);
virtual int link(const char* myName, int nameSize, int dstIp, int dstPort);
virtual int confirm(const char* myName, int nameSize, int index);
virtual int cancel(int index);
virtual int sendMsg(int index, const char* msg, int size);
private:
Busi* m_busi;
};
}
#endif /* hello_busi_h */
花了半天的時間寫完了底層庫,先來測試一下底層庫的連通性,我寫了一個程試程式,只列下核心檔案, 詳細請看github上。
void Test::testBusi()
{
m_busi = new Busi();
m_busi->init(this);
char ip[128];
printf("pleast input your name
");
fgets(m_name, 127, stdin);
printf("please input your select
");
printf("1 for link
");
printf("2 for auto link
");
int v;
scanf("%d", &v);
if(v == 1){
printf("please input the dst ip you want link
");
scanf("%s", ip);
int dstIp = inet_addr(ip);
m_busi->link(m_name, strlen(m_name)+1, dstIp, HELLO_COMM_SERVER_LISTEN_PORT);
}
else{
printf("now you can want link from others
");
}
}
void Test::sendMsg(const char *buffer, int size)
{
m_busi->sendMsg(m_dstIndex, buffer, size);
}
int Test::onInit(int myIp, int myPort)
{
struct in_addr addr;
addr.s_addr = myIp;
printf("on init, my ip:%s, my port:%d
", inet_ntoa(addr), myPort);
return HELLO_STATUS_OK;
}
int Test::onLink(int srcIndex, int srcIp, int srcPort, const char* srcName, int nameSize)
{
struct in_addr addr;
addr.s_addr = srcIp;
printf("on link from ip:%s, port:%d, name:%s
", inet_ntoa(addr), srcPort, srcName);
m_busi->confirm(m_name, strlen(m_name), srcIndex);
printf("now you can send msg to destination
");
g_linked = 1;
m_dstIndex = srcIndex;
return HELLO_STATUS_OK;
}
int Test::onConfirm(int srcIndex, const char* srcName, int nameSize)
{
printf("on confirm from index:%d, name:%s
", srcIndex, srcName);
m_dstIndex = srcIndex;
printf("now you can send msg to destination
");
g_linked = 1;
return HELLO_STATUS_OK;
}
int Test::onCancel(int srcIndex)
{
printf("on cancel from index:%d
", srcIndex);
return HELLO_STATUS_OK;
}
int Test::onMsg(int srcIndex, const char* msg, int size)
{
printf("on msg from index:%d, msg: size:%d
", srcIndex, size);
printf("msg:%s", msg);
return HELLO_STATUS_OK;
}
因為我有一臺mac, 一個ubuntu,所有測試時候,2邊都要編譯,mac是用xcode比較簡單,ubuntu上編寫makefile
framework:
BUSI_SRC=$(wildcard busi/*.cpp)
NET_SRC=$(wildcard net/*.cpp)
PACKAGE_SRC=$(wildcard package/*.cpp)
UTIL_SRC=$(wildcard util/*.cpp)
SRC=$(BUSI_SRC) $(NET_SRC) $(PACKAGE_SRC) $(UTIL_SRC)
OBJS=$(patsubst %.cpp, %.o, $(SRC))
CXXFLAGS += -D_WMD -pthread -std=c++11 -g -O0
LDFLAGS += -L/lib64 -pthread
LIB=../lib/libwmd.a
default: $(LIB)
$(LIB): $(OBJS)
rm -rf $@
ar -rs $@ $(OBJS)
clean:
-rm -rf $(OBJS)
.cpp:
$(CXX) -o $@ $< $(CXXFLAGS) $(LDFLAGS) $(LIBRARY) $(LIBS)
test
SRC=$(wildcard *.cpp)
OBJS=$(patsubst %.cpp, %.o, $(SRC))
CXXFLAGS += -std=c++11 -g -O0
LDFLAGS += ../lib/libwmd.a -L/lib64 -pthread
APP=./hello.out
default:$(APP)
clean:
-rm -rf $(OBJS)
-rm -rf $(APP)
$(APP): $(OBJS)
$(CXX) -o $@ $^ $(CXXFLAGS) $(LDFLAGS)
.cpp:
$(CXX) -g -o $@ $< $(CXXFLAGS) $(LDFLAGS) $(LIBRARY) $(LIBS)
生成的程式如下:
現在我們來實測一下連通性:
我讓mac做主動連線的一方,讓linux做被動連線。
然後試著各自問候一下吧
可以看到2者已經通了,我們們的底層庫搭建OK!
感興趣並助喜歡動手同學,可以 下載程式碼 實測一下。
寫一個你看我畫的程式吧
為了方便除錯,我選擇開發一個mac版的你看我畫。
建立工程
在xcode上建立一個spritekit工程
在storyboard上加入按鈕元素並繫結ViewController中的變數。
程式碼目錄設計
framework為底層庫,util為工具目錄,adaptor為適配層。
實現繪圖功能
建立一個自定義的view用來實現繪畫。
在實現上我用最簡單的繪圖API, 不過為了區分對手與我畫的,我用了2種顏色。
設定自定義滑鼠響應事件
並在程式碼裡建立1個scene用於載入自定義view.
上下層打通
object c 呼叫原生C++,我的做法是加一層代理。
我將程式碼結構設計如下
含義
CoreData | 應用層協議結構 |
---|---|
CoreAdaptor | object c 適配 |
CoreDelegate | 程式碼介面 |
Core | c++適配 |
適配架構
在開發的時候,我希望上層在傳送訊息時,不需要指定IP與埠,而只需要索引就行,因此在framework層
建立一個 地址與索引的對應關係。
所以適配層呼叫介面只需要指定index就行了
應用層通訊實現
結合之前設計的流程圖,這個遊戲過程的生命週期用viewcontroller 中的程式碼表示如下:
所以最終連線建立要麼在confirm後,要麼在onConfirm後。
start函式其實只是負責切換到畫圖場景
OK,整體程式碼寫完後,我們來演示一下效果。
程式演示
先看下截圖
明天我上傳下視訊,我畫的有點醜,不過沒關係,大家可以上github上拉下來自己畫。
https://github.com/70207/draw.git
相關文章
- 簡單設計一個JAVA並行處理工具類Java並行
- Golang併發程式設計程式通訊channel瞭解及簡單使用Golang程式設計
- C#網路程式設計-簡單的通訊原始碼C#程式設計原始碼
- openfoam並行通訊探索(一)並行
- 使用Scala模擬簡單的RPC通訊,Socket程式設計RPC程式設計
- 一個簡單的netty通訊的例子Netty
- 【設計和開發一套簡單自動化UI框架】UI框架
- 如何設計一個簡單的訊息中介軟體
- Delphi 簡單命名管道在兩個程式間通訊
- Linux網路程式設計之socket簡單通訊--客戶端程式碼Linux程式設計客戶端
- Java併發程式設計之執行緒安全、執行緒通訊Java程式設計執行緒
- 程式設計師修神之路--簡約而不簡單的分散式通訊基石程式設計師分散式
- 行動通訊概述(一)
- 一位德國程式設計師祕訣:如何通過3個簡單步驟成為高階開發人員?程式設計師
- .NET併發程式設計-資料並行程式設計並行
- 用flask開發部落格(1)——第一個簡單程式Flask
- Linux網路程式設計之socket簡單通訊TCP--服務端程式碼Linux程式設計TCP服務端
- parallel: 一個簡單的並行執行Go迴圈的庫Parallel並行Go
- 序列通訊與並行通訊的區別並行
- 網路通訊程式設計程式設計
- 一個簡單混合協議通訊列子,物聯網和網際網路通訊。協議
- 一個網路通訊開發庫原始碼原始碼
- 網路通訊2:TCP簡單通訊TCP
- 使用Dockerfile建立一個tomcat映象,並執行一個簡單war包DockerTomcat
- 一個簡單的JavaScript函數語言程式設計教程JavaScript函數程式設計
- VC++串列埠程式設計之簡訊應用開發(轉)C++串列埠程式設計
- 簡單的Socket通訊
- Java併發程式設計(04):執行緒間通訊,等待/通知機制Java程式設計執行緒
- Java併發程式設計序列之JUC中Condition執行緒通訊Java程式設計執行緒
- golang開發一個簡單的grpcGolangRPC
- 併發程式設計和並行程式設計程式設計並行行程
- 快速入門android AIDL(開啟多程式並進行通訊)AndroidAI
- 簡單區分WiFi通訊和WLAN通訊WiFi
- 利用jmeter做一個簡單的效能測試並進行引數化設定JMeter
- 程式通訊 執行緒通訊執行緒
- 微信小程式之簡單開發操作(一)微信小程式
- 一個JS程式設計師對機器學習的概念簡單手記JS程式設計師機器學習
- 做一個優秀的程式設計師沒那麼簡單程式設計師