您的位置:首页 > 其它

用C的输入输出流 简单实现即时通讯

2017-08-16 00:00 253 查看

一、首先搭建一个简单的服务器

Python服务器代码下载:

python服务器:链接: https://pan.baidu.com/s/1hsd3ZYO 密码: gyxg



其中已包含了下文需要安装的 zope.interface 和 twisted 两个文件,免去了你再去官网下载。

ps:该源码只能在python2运行环境成功执行,python3虽然能连接但是无法发送数据。

查看python版本方法,直接在命令行输入python



启动服务器的方法:

1.打开终端,用cd 命令进到chatserver.py这个文件所在的路劲。

2.输入python chatserver.py



如果报了这个没有twisted这个错误的话,那就要安装一下了。

安装方法:

1.安装twisted. 需要先安装zope.interface,才能安装twisted.

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

下载后你会得到一个

的压缩包,

解压后的文件目录为:



然后在终端先进入这个名为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安装成功了

现在,再次启动服务器试试:



启动成功啦。

二、编写客户端代码

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,我们客户端的内容传到了服务器了。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: