在日常學(xué)習(xí)、工作或生活中,大家總少不了接觸作文或者范文吧,通過文章可以把我們那些零零散散的思想,聚集在一塊。寫范文的時(shí)候需要注意什么呢?有哪些格式需要注意呢?下面我給大家整理了一些優(yōu)秀范文,希望能夠幫助到大家,我們一起來看一看吧。
不同坐標(biāo)系之間的轉(zhuǎn)換方法篇一
引導(dǎo)語:網(wǎng)絡(luò)傳輸中,數(shù)據(jù)包與數(shù)據(jù)流的相互轉(zhuǎn)換都有哪些方法呢?以下是小編整理的包與流之間的轉(zhuǎn)換方法,歡迎參考閱讀!
這種辦法粗暴簡(jiǎn)單,我們使用一個(gè)特殊字符來作為包與包之間的分隔符,不過這個(gè)分隔符要特殊,特殊到幾乎不出現(xiàn)在包的內(nèi)容當(dāng)中,否則會(huì)影響接收方切割包的過程。
作為發(fā)送方,我們可以用如下代碼(示意用):
#define kseparatorchar @"¤"
+ (nsstring*)encodetextpayload:(nsstring*)payload {
nsstring* str = [nsstring stringwithformat:@"%@%@", kseparatorchar, payload];
return str;
}
¤ 就是一個(gè)非常特殊的字符,一般應(yīng)用層的文本都不會(huì)涉及到,所以可以用作我們的特殊分隔符。接收端只需要以 ¤ 為分隔符,再把數(shù)據(jù)做一次切割即可:
+ (nsstring*)decodetextpayloadstring:(nsstring*)str {
nsstring* payload;
nsarray* arr = [str componentsseparatedbystring:kseparatorchar];
if ( < 2) {
return nil;
}
payload = arr[1];
return payload;
}
這種做法的缺陷也是顯而易見的,必須嚴(yán)格要求包體中不會(huì)出現(xiàn)該特殊字符,所以這種辦法只能應(yīng)用于非常特殊的場(chǎng)景。
這種辦法也是粗暴簡(jiǎn)單,甚至不需要分隔符,每次接收方從 stream 中取出固定長(zhǎng)度的字節(jié),還原成一個(gè)包,代碼也比較簡(jiǎn)單,在 receive() 回調(diào)里,每次檢查是否達(dá)到了固定的長(zhǎng)度,是則取出固定長(zhǎng)度還原,否則繼續(xù)等待,代碼就不演示啦。
這種做法的缺陷就更大了,會(huì)造成包體的浪費(fèi),無法適應(yīng)不同大小的包。
之前一篇介紹自定義通訊協(xié)議的文章里,簡(jiǎn)單的提到過如何設(shè)計(jì)一個(gè)可用的協(xié)議,這里我們具體看下代碼。
當(dāng)我們需要描述可變長(zhǎng)度的`包時(shí),需要定義一個(gè) header 來詳細(xì)描述包相關(guān)的信息,比如最簡(jiǎn)單的,記錄包的長(zhǎng)度。如何記錄包的大小呢?我們可以用位操作的特性,來將應(yīng)用層的 int 值放入到包的 header 中,代碼如下(代碼摘自以前的項(xiàng)目,稍有改動(dòng)):
- (nsdata*)encodedata:(nsdata*)data withheader:(nsstring*)header {
int datasize = (int);
char buffer[4];
buffer[0] = datasize >> 24;
buffer[1] = (datasize << 8) >> 24;
buffer[2] = (datasize << 16) >> 24;
buffer[3] = (datasize << 24) >> 24;
nsmutabledata* packet = [nsmutabledata new];
[packet appendbytes:[header utf8string] length:2];
[packet appendbytes:buffer length:4];
[packet appenddata:data];
return packet;
}
這是一個(gè)通用的技巧,當(dāng)我們需要在 stream 中記錄可變長(zhǎng)度的數(shù)據(jù)時(shí),都可以用這種位操作來做轉(zhuǎn)換,只需要 2 個(gè)字節(jié)的長(zhǎng)度,即可記錄長(zhǎng)達(dá) 64 kb 的數(shù)據(jù)長(zhǎng)度,4 個(gè)字節(jié)則能記錄長(zhǎng)達(dá) 4 gb 的長(zhǎng)度。
接收方在收到 nsdata 之后,可以先讀取 4 個(gè)字節(jié)的長(zhǎng)度信息,還原成 int 值,再讀取 int 值所記錄的字節(jié)數(shù),這些字節(jié)就是我們的包了,代碼如下:
- (tdecodeddata*)decodedata:(nsdata*)data {
tdecodeddata* d = [tdecodeddata new];
if ( < 6) { //minimal packet length
return nil;
}
if ([headerstr isequaltostring:kpacketstreamheader] == true) {
int realsize = 0;
unsigned char buffer[4];
[data getbytes:buffer range:nsmakerange(2, 4)];
realsize += buffer[0] << 24;
realsize += buffer[1] << 16;
realsize += buffer[2] << 8;
realsize += buffer[3] << 0;
if ( - 6 < realsize) {
return nil;
}
= kpacketstreamheader;
nsdata* payloadbytes = [data subdatawithrange:nsmakerange(6, realsize)];
if ( > 0) {
ddata = payloadbytes;
}
//remove from data
int handledlength = 6 + realsize;
nsdata* nd = [nsdata datawithbytes: + handledlength length:-handledlength];
ddata = nd;
}
return d;
}
上面的代碼主要是向大家展示,如何以添加 header 的方式,來記錄可變長(zhǎng)度的包體信息。如此,發(fā)送方所發(fā)送的 nsdata 就和接收方所接受的 nsdata 一一對(duì)應(yīng)起來了,就就不存在所謂的粘包和拆包問題了。
我們之所以可以對(duì)一個(gè) stream 做切分,是因?yàn)?tcp 已經(jīng)做了可靠傳輸?shù)谋WC,接收方收到的 stream 和發(fā)送方發(fā)送的 stream 嚴(yán)格一致,一個(gè)字節(jié)都不會(huì)差,所以我們只需要先讀取長(zhǎng)度值,再按長(zhǎng)度值讀取后續(xù)的數(shù)據(jù),就能把一個(gè) stream 分割成一個(gè)個(gè)的 nsdata,這些分割好的 nsdata 就是發(fā)送方所發(fā)送的包了。
接收方將 stream 分割成 nsdata 之后,需要進(jìn)一步將 data 反序列化成應(yīng)用層的包,這里就必須提到 google 開源的 protobuf 了,序列化和反序列化神器,造福了無數(shù)的框架和應(yīng)用,甚至有 objective c 的版本。
s("content_relate");【包與流之間的轉(zhuǎn)換方法】相關(guān)文章:
java進(jìn)制之間的轉(zhuǎn)換
10-01
word文件的轉(zhuǎn)換方法
10-06
php ascii碼與字符串相互轉(zhuǎn)換的方法
09-11
c語言中網(wǎng)絡(luò)地址與二進(jìn)制數(shù)之間轉(zhuǎn)換
11-20
java中float類型的范圍及其與十六進(jìn)制的轉(zhuǎn)換方法
11-28
php字母大小寫轉(zhuǎn)換的方法
08-21
java輸入數(shù)據(jù)流的方法有哪些
12-07
java中的stream流的解析與應(yīng)用
12-01
c++中時(shí)間與時(shí)間戳的轉(zhuǎn)換
10-04
word表格中數(shù)據(jù)縱橫轉(zhuǎn)換的方法和技巧
09-21