CocoaAsyncSocket 網絡通信使用之http協議測試(三)

CocoaAsyncSocket 網絡通信使用之http協議測試(三)


通過前一篇CocoaAsyncSocket網絡通信使用之數據編碼和解碼(二),我們已經搭建好了socket的框架。

框架主要分爲以下5個模塊:

1-網絡連接模塊(socket connection)

2-數據協議框架(socket packet content protocol)

3-發送數據前的編碼模塊(socket encoder protocol)

4-接收數據後的解碼模塊(socket decoder protocol)

5-各模塊的組合調用(socket service)


簡述:

通過5個模塊的協同工作,可以方便的處理tcp通信的擴展。

因爲不方便公開外網服務,不能很好的測試自定義協議的編碼器/解碼器,

只是簡單的對網絡連接成功做了打印,現在我們來實踐下框架的擴展用法。


http(HyperText Transport Protocol,超文本傳輸協議)

其實現在網上隨處可見http協議的服務,而http是基於tcp/ip的,我們正好可以借用http來實踐我們的用法。

現在就針對http協議來實現我們的編碼器/解碼器。


http協議內容很多,本文主要是測試sokcet框架,確認框架的完整性,拓展性,具體協議內容請自行搜索(http協議格式)。

以下是實現編碼器/解碼器時,學習的網址:(強烈建議學習一下,否則不好理解http編碼器/解碼器的內容哦)

http://blog.csdn.net/gueter/article/details/1524447


http協議的測試[編碼器/解碼器]

代碼中只是測試用例,並非真實完整實現,看官勿噴。


RHPacketHttpRequest.h文件:(http協議的測試請求包)

#import "RHPacketBody.h"

@interface RHPacketHttpRequest : RHPacketBody

@property (nonatomic, copy) NSString *requestPath;
@property (nonatomic, copy) NSString *host;
@property (nonatomic, copy) NSString *connection;

@end

RHPacketHttpRequest.m文件:(只是測試,默認寫了幾個請求參數)

#import "RHPacketHttpRequest.h"

@implementation RHPacketHttpRequest

- (instancetype)init
{
    if (self = [super init]) {
        _requestPath = @"GET /index.html HTTP/1.1";
        _host = @"Host:www.baidu.com";
        _connection = @"Connection:close";
    }
    return self;
}

- (NSData *)data
{
    NSData *crlfData = [@"\r\n" dataUsingEncoding:NSASCIIStringEncoding];<span style="font-family: Arial, Helvetica, sans-serif;">//回車換行是http協議中每個字段的分隔符</span>
    
    NSMutableData *packetData = [[NSMutableData alloc] init];
    [packetData appendData:[_requestPath dataUsingEncoding:NSASCIIStringEncoding]];
    [packetData appendData:crlfData];
    [packetData appendData:[_host dataUsingEncoding:NSASCIIStringEncoding]];
    [packetData appendData:crlfData];
    [packetData appendData:[_connection dataUsingEncoding:NSASCIIStringEncoding]];
    [packetData appendData:crlfData];
//    [packetData appendData:[@"Accept:image/webp,*/*;q=0.8" dataUsingEncoding:NSASCIIStringEncoding]];
//    [packetData appendData:crlfData];
    return packetData;
}

@end


RHSocketHttpEncoder.h文件:(http協議的測試編碼器)

#import <Foundation/Foundation.h>
#import "RHSocketEncoderProtocol.h"

@interface RHSocketHttpEncoder : NSObject <RHSocketEncoderProtocol>

@end


RHSocketHttpEncoder.m文件:

#import "RHSocketHttpEncoder.h"
#import "RHSocketConfig.h"

@implementation RHSocketHttpEncoder

- (void)encodePacket:(id<RHSocketPacketContent>)packet encoderOutput:(id<RHSocketEncoderOutputDelegate>)output
{
    NSData *data = [packet data];
    NSMutableData *sendData = [NSMutableData dataWithData:data];
    NSData *crlfData = [@"\r\n" dataUsingEncoding:NSASCIIStringEncoding];//回車換行是http協議中每個字段的分隔符,也是請求的結束符
    [sendData appendData:crlfData];
    
    NSTimeInterval timeout = [packet timeout];
    NSInteger tag = [packet tag];
    RHSocketLog(@"tag:%ld, timeout: %f, data: %@", (long)tag, timeout, sendData);
    [output didEncode:sendData timeout:timeout tag:tag];
}

@end


RHSocketHttpDecoder.h文件:(http協議的測試解碼器)

#import <Foundation/Foundation.h>
#import "RHSocketDecoderProtocol.h"

@interface RHSocketHttpDecoder : NSObject <RHSocketDecoderProtocol>

@end


RHSocketHttpDecoder.m文件:

#import "RHSocketHttpDecoder.h"
#import "RHSocketConfig.h"
#import "RHPacketHttpResponse.h"

@interface RHSocketHttpDecoder ()
{
    NSMutableData *_receiveData;
}

@end

@implementation RHSocketHttpDecoder

- (NSUInteger)decodeData:(NSData *)data decoderOutput:(id<RHSocketDecoderOutputDelegate>)output tag:(long)tag
{
    @synchronized(self) {
        if (_receiveData) {
            [_receiveData appendData:data];
        } else {
            _receiveData = [NSMutableData dataWithData:data];
        }
        
        NSUInteger dataLen = _receiveData.length;
        NSInteger headIndex = 0;
        int crlfCount = 0;
        
        for (NSInteger i=0; i<dataLen; i++) {
            uint8_t byte;
            [_receiveData getBytes:&byte range:NSMakeRange(i, 1)];
            if (byte == 0x0a) {//0x0a是http協議中的字段分隔符,我們只是測試程序,簡單解析對應返回數據,然後打印
                crlfCount++;
            }
            if (crlfCount == 2) {
                NSInteger packetLen = i - headIndex;
                NSData *packetData = [_receiveData subdataWithRange:NSMakeRange(headIndex, packetLen)];
                RHPacketHttpResponse *rsp = [[RHPacketHttpResponse alloc] initWithData:packetData];
                [output didDecode:rsp tag:0];
                headIndex = i + 1;
                crlfCount = 0;
            }
        }
        
        NSData *remainData = [_receiveData subdataWithRange:NSMakeRange(headIndex, dataLen-headIndex)];
        [_receiveData setData:remainData];
        
        return _receiveData.length;
    }//@synchronized
}

@end

測試調用方法:

    NSString *host = @"www.baidu.com";
    int port = 80;
    
    [RHSocketService sharedInstance].encoder = [[RHSocketHttpEncoder alloc] init];
    [RHSocketService sharedInstance].decoder = [[RHSocketHttpDecoder alloc] init];
    [[RHSocketService sharedInstance] startServiceWithHost:host port:port];

也可以繼承RHSocketService對象,重載裏面的接口方法,增加短線重連等等邏輯。


總結:

以上就是針對http協議實現的測試代碼,我們可以看到,socket框架中的代碼無需修改,完全可以共用。

這樣以後即使是不同應用,不同的業務協議,也不需要重複造輪子了。

文章中都是以代碼的方式呈現的,習慣看代碼的同學可能比較易懂,但是缺乏整體框架的說明描述。

下一篇,針對當前的框架,繪製uml類圖結構。

---------------------

轉載請註明出處,謝謝

email: [email protected]

qq: 410289616

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章