簡單設計並開發一個行動通訊程式
網路越來越好,手機之間的互動已經是常態,王者榮耀、微信實時視訊等,已經將多屏互動推到各到各種應用場景。
為了讓大家能清楚地瞭解多屏互動,我將結合例項對移動裝置實時通訊進行研究,並系統性地呈現一些解決方案。
最開始,我嘗試給大家展示如何建立一個最簡單的點對點通訊。
萬事開頭難,先假定一下需求:
區域網內通訊。
寫一個你看我畫的程式。
純客戶端(一開始,我不打算讓伺服器參與)。
下面對需求進行進一步的分析。
需求分析
我做了一個簡單的原型設計,如下圖,其實真正的狀態比這個稍複雜,這裡提供一下 原型連結
需求原型
從原型上看,我們的流程應該是下圖的形式。
流程圖
下面我們進行架構設計與開發選型了。
架構設計
基於前文的需求假定進行簡單設計網路模型,我將目標的網路分拆成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程式設計
- 一個簡單的netty通訊的例子Netty
- openfoam並行通訊探索(一)並行
- 如何設計一個簡單的訊息中介軟體
- 程式設計師修神之路--簡約而不簡單的分散式通訊基石程式設計師分散式
- Java併發程式設計之執行緒安全、執行緒通訊Java程式設計執行緒
- .NET併發程式設計-資料並行程式設計並行
- 一位德國程式設計師祕訣:如何通過3個簡單步驟成為高階開發人員?程式設計師
- 使用Dockerfile建立一個tomcat映象,並執行一個簡單war包DockerTomcat
- parallel: 一個簡單的並行執行Go迴圈的庫Parallel並行Go
- 簡單學:併發程式設計之 ThreadLocal程式設計thread
- 行動通訊概述(一)
- golang開發一個簡單的grpcGolangRPC
- 設計一個簡單的devops系統dev
- Java併發程式設計序列之JUC中Condition執行緒通訊Java程式設計執行緒
- 併發程式設計-8.並行資料結構和並行Linq程式設計並行資料結構
- 在鴻蒙開發中,如何實現一個簡單的應用間通訊(Event Bus)功能?鴻蒙
- 網路通訊程式設計程式設計
- Python 併發程式設計(四):詳解 Python 執行緒訊息通訊機制Python程式設計執行緒
- .NET併發程式設計-任務函式並行程式設計函式並行
- Vular 開發手記 #1:設計並實現一個拼插式應用程式框架框架
- 一個簡單混合協議通訊列子,物聯網和網際網路通訊。協議
- Java併發程式設計(04):執行緒間通訊,等待/通知機制Java程式設計執行緒
- windows程式設計師開發linux程式的頭一個月Windows程式設計師Linux
- 序列通訊與並行通訊的區別並行
- 如何通過幾個簡單的步驟編寫一個漂亮的初級開發者簡歷
- 簡單的Java實現Netty進行通訊JavaNetty
- 網路通訊2:TCP簡單通訊TCP
- 一個簡單java程式的執行全過程Java
- 來來,一起設計一個簡單的活動釋出系統
- 網路程式設計-Socket通訊程式設計
- 系統程式設計——管道通訊程式設計
- 併發程式設計-6.並行程式設計概念程式設計並行行程
- Linux系統程式設計之程式間通訊方式:管道(一)Linux程式設計
- 簡單的Socket通訊
- 最簡單的C程式設計--順序程式設計C程式程式設計
- Golang併發程式設計中select簡單瞭解Golang程式設計
- Go語言併發程式設計簡單入門Go程式設計