寫了一個socket的程序,可以和本地的服務器進行通信,要先和服務器建立鏈接,然后發送登錄信息,驗證成功,就可以和服務器通信了
1 頁面截圖
2 點擊鏈接服務器,可以鏈接服務器,服務器的ip地址為:127.0.0.1 端口為 12345;
3 點擊鏈接服務器之后,打印信息如下
4 點擊登錄,會向服務器發送登錄信息: iam:zhangsan, 然后會客戶端會顯示登錄成功
5 比如輸入chongqingyoudian?
6 在服務器控制臺就能看到客戶端發送的信息
客戶端代碼如下
1 // 2 // ViewController.m 3 // 05.聊天室 4 // 5 // Created by apple on 14/12/5. 6 // Copyright (c) 2014年 heima. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 11 @interface ViewController ()<NSStreamDelegate,UITextFieldDelegate,UITableViewDataSource,UITableViewDelegate>{ 12 NSInputStream *_inputStream;//對應輸入流 13 NSOutputStream *_outputStream;//對應輸出流 14 } 15 @property (weak, nonatomic) IBOutlet NSLayoutConstraint *inputViewConstraint; 16 @property (weak, nonatomic) IBOutlet UITableView *tableView; 17 18 @property (nonatomic, strong) NSMutableArray *chatMsgs;//聊天消息數組 19 20 @end 21 22 @implementation ViewController 23 24 -(NSMutableArray *)chatMsgs{ 25 if (!_chatMsgs) { 26 _chatMsgs = [NSMutableArray array]; 27 } 28 29 return _chatMsgs; 30 } 31 32 - (void)viewDidLoad { 33 [super viewDidLoad]; 34 // Do any additional setup after loading the view, typically from a nib. 35 36 37 // 2.收發數據 38 // 做一個聊天 39 // 1.用戶登錄 40 // 2.收發數據 41 42 // 監聽鍵盤 43 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(kbFrmWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil]; 44 } 45 46 47 -(void)kbFrmWillChange:(NSNotification *)noti{ 48 NSLog(@"%@",noti.userInfo); 49 50 // 獲取窗口的高度 51 52 CGFloat windowH = [UIScreen mainScreen].bounds.size.height; 53 54 55 56 // 鍵盤結束的Frm 57 CGRect kbEndFrm = [noti.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; 58 // 獲取鍵盤結束的y值 59 CGFloat kbEndY = kbEndFrm.origin.y; 60 61 62 self.inputViewConstraint.constant = windowH - kbEndY; 63 } 64 65 -(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{ 66 NSLog(@"%@",[NSThread currentThread]); 67 68 // NSStreamEventOpenCompleted = 1UL << 0,//輸入輸出流打開完成 69 // NSStreamEventHasBytesAvailable = 1UL << 1,//有字節可讀 70 // NSStreamEventHasSpaceAvailable = 1UL << 2,//可以發放字節 71 // NSStreamEventErrorOccurred = 1UL << 3,// 連接出現錯誤 72 // NSStreamEventEndEncountered = 1UL << 4// 連接結束 73 switch (eventCode) { 74 case NSStreamEventOpenCompleted: 75 NSLog(@"登錄服務器成功,輸入輸出流打開完成"); 76 break; 77 case NSStreamEventHasBytesAvailable: 78 NSLog(@"有字節可讀"); 79 [self readData]; 80 break; 81 case NSStreamEventHasSpaceAvailable: 82 NSLog(@"可以發送字節"); 83 break; 84 case NSStreamEventErrorOccurred: 85 NSLog(@" 連接出現錯誤"); 86 break; 87 case NSStreamEventEndEncountered: 88 NSLog(@"連接結束"); 89 90 // 關閉輸入輸出流 91 [_inputStream close]; 92 [_outputStream close]; 93 94 // 從主運行循環移除 95 [_inputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 96 [_outputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 97 break; 98 default: 99 break; 100 } 101 102 } 103 #pragma mark 在這里先和服務器建立鏈接 104 - (IBAction)connectToHost:(id)sender { 105 // 1.建立連接 106 NSString *host = @"127.0.0.1"; 107 int port = 12345; 108 109 // 定義C語言輸入輸出流 110 CFReadStreamRef readStream; 111 CFWriteStreamRef writeStream; 112 CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream); 113 114 // 把C語言的輸入輸出流轉化成OC對象 115 _inputStream = (__bridge NSInputStream *)(readStream); 116 _outputStream = (__bridge NSOutputStream *)(writeStream); 117 118 119 // 設置代理 120 _inputStream.delegate = self; 121 _outputStream.delegate = self; 122 123 124 // 把輸入輸入流添加到主運行循環 125 // 不添加主運行循環 代理有可能不工作 126 [_inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 127 [_outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 128 129 // 打開輸入輸出流 130 [_inputStream open]; 131 [_outputStream open]; 132 } 133 134 #pragma mark 在這里發送登錄的信息 135 - (IBAction)loginBtnClick:(id)sender { 136 137 // 登錄 138 // 發送用戶名和密碼 139 // 在這里做的時候,只發用戶名,密碼就不用發送 140 141 // 如果要登錄,發送的數據格式為 "iam:zhangsan"; 142 // 如果要發送聊天消息,數據格式為 "msg:did you have dinner"; 143 144 //登錄的指令 145 NSString *loginStr = @"iam:zhangsan"; 146 147 //把Str轉成NSData 148 NSData *data = [loginStr dataUsingEncoding:NSUTF8StringEncoding]; 149 150 151 [_outputStream write:data.bytes maxLength:data.length]; 152 } 153 154 #pragma mark 讀了服務器返回的數據 155 -(void)readData{ 156 157 //建立一個緩沖區 可以放1024個字節 158 uint8_t buf[1024]; 159 160 // 返回實際裝的字節數 161 NSInteger len = [_inputStream read:buf maxLength:sizeof(buf)]; 162 163 // 把字節數組轉化成字符串 164 NSData *data = [NSData dataWithBytes:buf length:len]; 165 166 // 從服務器接收到的數據 167 NSString *recStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 168 169 NSLog(@"%@",recStr); 170 171 [self reloadDataWithText:recStr]; 172 173 } 174 175 -(BOOL)textFieldShouldReturn:(UITextField *)textField{ 176 177 NSString *text = textField.text; 178 179 NSLog(@"%@",text); 180 // 聊天信息 181 NSString *msgStr = [NSString stringWithFormat:@"msg:%@",text]; 182 183 //把Str轉成NSData 184 NSData *data = [msgStr dataUsingEncoding:NSUTF8StringEncoding]; 185 186 // 刷新表格 187 [self reloadDataWithText:msgStr]; 188 189 // 發送數據 190 [_outputStream write:data.bytes maxLength:data.length]; 191 192 // 發送完數據,清空textField 193 textField.text = nil; 194 195 return YES; 196 } 197 198 -(void)reloadDataWithText:(NSString *)text{ 199 [self.chatMsgs addObject:text]; 200 201 [self.tableView reloadData]; 202 203 // 數據多,應該往上滾動 204 NSIndexPath *lastPath = [NSIndexPath indexPathForRow:self.chatMsgs.count - 1 inSection:0]; 205 [self.tableView scrollToRowAtIndexPath:lastPath atScrollPosition:UITableViewScrollPositionBottom animated:YES]; 206 } 207 208 #pragma mark 表格的數據源 209 210 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 211 return self.chatMsgs.count; 212 } 213 214 215 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 216 { 217 static NSString *ID = @"Cell"; 218 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; 219 220 cell.textLabel.text = self.chatMsgs[indexPath.row]; 221 222 return cell; 223 } 224 225 -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{ 226 [self.view endEditing:YES]; 227 } 228 @end
服務器端代碼
1 from twisted.internet.protocol import Protocol, Factory 2 from twisted.internet import reactor 3 4 5 class IphoneChat(Protocol): 6 def connectionMade(self): 7 #self.transport.write("""connected""") 8 self.factory.clients.append(self) 9 print "clients are ", self.factory.clients 10 11 def connectionLost(self, reason): 12 self.factory.clients.remove(self) 13 14 def dataReceived(self, data): 15 #print "data is ", data 16 a = data.split(':') 17 if len(a) > 1: 18 command = a[0] 19 content = a[1] 20 21 msg = "" 22 if command == "iam": 23 self.name = content 24 msg = self.name + " has joined" 25 26 elif command == "msg": 27 msg = self.name + ": " + content 28 29 print msg 30 31 for c in self.factory.clients: 32 c.message(msg) 33 34 def message(self, message): 35 self.transport.write(message + '\n') 36 37 38 factory = Factory() 39 factory.protocol = IphoneChat 40 factory.clients = [] 41 42 reactor.listenTCP(12345, factory) 43 print "Iphone Chat server started" 44 reactor.run()
?