一个简单的socket通信小demo
写了一个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()