用C的輸入輸出流 簡單實現即時通信

1、首先搭建一個簡單的服務器

Python服務器代碼下載:

python服務器:連接: https://pan.baidu.com/s/1hsd3ZYO  密碼: gyxgpython

其中已包含了下文須要安裝的 zope.interface  和  twisted  兩個文件,免去了你再去官網下載。數據庫

ps:該源碼只能在python2運行環境成功執行,python3雖然能鏈接可是沒法發送數據。數組

查看python版本方法,直接在命令行輸入python服務器

 

 

啓動服務器的方法:

1.打開終端,用cd 命令進到chatserver.py這個文件所在的路勁。   oop

2.輸入python chatserver.py  ui

若是報了這個沒有twisted這個錯誤的話,那就要安裝一下了。spa

安裝方法:

1.安裝twisted. 須要先安裝zope.interface,才能安裝twisted.

下載地址:https://pypi.python.org/pypi/zope.interface (上面已提供,不用下載了)命令行

下載後你會獲得一個的壓縮包,代理

解壓後的文件目錄爲:code

而後在終端先進入這個名爲zope.interface-4.1.3的文件夾路徑,而後輸入sudo python setup.py install  接着要求輸入一下電腦密碼,即可以安裝zope.interface。

 

 

2.安裝twisted

下載地址:https://twistedmatrix.com/trac/wiki/Downloads  (上面已提供,不用下載了)

解壓後目錄:

安裝方法和上面同樣,sudo python setup.py install  接着輸入一下電腦密碼,即可以安裝twisted。

驗證twisted是否安裝成功

①先輸入python    回車

②輸入import twisted    回車     沒有任何提示,說明twisted安裝成功了

 

如今,再次啓動服務器試試:

啓動成功啦。

 

2、編寫客戶端代碼

1.搭建簡易UI

 

2.編寫 鏈接服務器 的BarButtonItem 方法:

//1.鏈接服務器
- (IBAction)connect:(id)sender {
    
    //創建鏈接
    NSString *host = @"127.0.0.1";
    int port = 12345;
    
    //定義輸入輸出流
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;
    CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);
    
    
    //把C語言的輸入輸出流轉化成OC對象
    _inputStream = (__bridge NSInputStream *)(readStream);
    _outputStream = (__bridge NSOutputStream *)(writeStream);
    
    
    //設置代理 監聽鏈接成功狀況
    _inputStream.delegate = self;
    _outputStream.delegate = self;
    
    
    //把輸入輸出流添加到主運行循環(不添加主運行循環,代理可能不工做)
    [_inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    [_outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    
    
    //打開輸入輸出流
    [_inputStream open];
    [_outputStream open];
    
    
}

 

3.編寫代理方法:(當上一步的 鏈接服務器 操做成功後,會走下面的代理方法,打印輸入輸出流打開完成 和 能夠發送字節, 該方法會在多種狀況下調用,具體看下面的枚舉說明)

//代理方法
-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{
    NSLog(@"%@",aStream);
    
    /*
    NSStreamEventOpenCompleted = 1UL << 0,      //輸入輸出流打開完成
    NSStreamEventHasBytesAvailable = 1UL << 1,  //服務器有返回字節
    NSStreamEventHasSpaceAvailable = 1UL << 2,  //能夠發送字節
    NSStreamEventErrorOccurred = 1UL << 3,      //鏈接出現錯誤
    NSStreamEventEndEncountered = 1UL << 4      //鏈接結束
    */
    switch (eventCode) {
        case NSStreamEventOpenCompleted:
            NSLog(@"輸入輸出流打開完成");
            break;
            
        case NSStreamEventHasBytesAvailable:
            NSLog(@"服務器有返回字節");
            
            //讀取服務器返回的數據
            [self readData];
            
            break;
            
        case NSStreamEventHasSpaceAvailable:
            NSLog(@"能夠發送字節");
            break;
            
        case NSStreamEventErrorOccurred:
            NSLog(@"鏈接出現錯誤");
            break;
            
        case NSStreamEventEndEncountered:
            NSLog(@"鏈接結束");
            
            //關閉輸入流
            [_inputStream close];
            [_outputStream class];
            
            //從主運行循環移除
            [_inputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
            [_outputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
            break;
       
        default:
            break;
    }
}

讀取數據庫返回的數據 方法

//讀取服務器返回的數據
-(void)readData{
    
    //創建緩衝區,即:建立一個能夠放1024個字節 的字節數組
    uint8_t buf[1024];
    
    
    //返回時間裝的字節數
    NSInteger len = [_inputStream read:buf maxLength:sizeof(buf)];
    
    //把字節數組轉化成字符串 ,把len的長度的字符 放到buf中
    NSData *data = [NSData dataWithBytes:buf length:len];
    
    //從服務器接收到的數據
    NSString *recStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    
    NSLog(@"%@",recStr);
    
}

 

 

4.編寫登陸方法 (登陸方法中,咱們有作發送數據給服務器,一旦登陸成功了,服務器會給出響應數據的,所以會調用 第3步驟的代理方法,控制檯打印服務器有返回字節)

//2.登陸 (會發送用戶名給服務器)
- (IBAction)login:(id)sender {
    
    //發送用戶名和密碼(我這裏只發了用戶名,沒有密碼)
    
    /*
     服務器規定:
     若是要登陸,發送的數據格式爲:"iam:zhangsan";
     若是要發送聊天消息,數據格式爲:"msg:did you have dinner";
     */
    //登陸指令
    NSString *loginStr = @"iam:zhangsan";
    
    //把NSString 轉成 NSdata
    NSData *data = [loginStr dataUsingEncoding:NSUTF8StringEncoding];
    
    //第一個參數(nonnull const uint8_t *) :要求傳一個uint8 * 類型的參數,這或其實就是unsigned char *
    [_outputStream write:data.bytes maxLength:data.length];
    
    
}

 

5.編寫發送數據方法

//點擊鍵盤上的return 發送消息
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
    NSString *text = textField.text;
    NSLog(@"%@",text);
    
    //聊天消息
    NSString *msgStr = [NSString stringWithFormat:@"msg:%@",text];
    
    //把NSString 轉成 NSdata
    NSData *data = [msgStr dataUsingEncoding:NSUTF8StringEncoding];
    
    //第一個參數(nonnull const uint8_t *) :要求傳一個uint8 * 類型的參數,這或其實就是unsigned char *
    [_outputStream write:data.bytes maxLength:data.length];
    
    return YES;
}

到此爲止就完成了用輸入輸出流寫了一個簡單的即時通信的例子。

 

 

演示:

1.點擊鏈接服務器按鈕:控制檯打印以下,能夠看到輸入輸出流分別打開,而且能夠發送字節

2.點擊登陸按鈕:控制檯打印以下,能夠看到服務器返回了zhangsan has joined

3.在TextField中輸入要發送的內容,而後點擊鍵盤上的return。 能夠看到命令行中出現了qwer,咱們客戶端的內容傳到了服務器了。

相關文章
相關標籤/搜索