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



Python服务器代码下载:

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

c语言 python 共享内存 c和python通信_服务器

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

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

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

c语言 python 共享内存 c和python通信_服务器_02

 

 



启动服务器的方法:

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

2.输入python chatserver.py  

c语言 python 共享内存 c和python通信_c/c++_03

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



安装方法:



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

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

下载后你会得到一个

c语言 python 共享内存 c和python通信_c语言 python 共享内存_04

的压缩包,

解压后的文件目录为:

c语言 python 共享内存 c和python通信_服务器_05

然后在终端先进入这个名为zope.interface-4.1.3的文件夹路径,然后输入sudo python setup.py install  接着要求输入一下电脑密码,便可以安装zope.interface。

c语言 python 共享内存 c和python通信_c/c++_06

 

 



2.安装twisted

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

解压后目录:

c语言 python 共享内存 c和python通信_python_07

安装方法和上面一样,sudo python setup.py install  接着输入一下电脑密码,便可以安装twisted。



验证twisted是否安装成功

c语言 python 共享内存 c和python通信_c/c++_08

①先输入python    回车

②输入import twisted    回车     没有任何提示,说明twisted安装成功了

 



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

c语言 python 共享内存 c和python通信_ui_09

启动成功啦。

 



二、编写客户端代码

1.搭建简易UI

c语言 python 共享内存 c和python通信_ui_10

 

2.编写 连接服务器

//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.点击连接服务器按钮:控制台打印如下,可以看到输入输出流分别打开,并且可以发送字节

c语言 python 共享内存 c和python通信_c/c++_11

2.点击登录按钮:控制台打印如下,可以看到服务器返回了zhangsan has joined

c语言 python 共享内存 c和python通信_ui_12

3.在TextField中输入要发送的内容,然后点击键盘上的return。 可以看到命令行中出现了qwer,我们客户端的内容传到了服务器了。

c语言 python 共享内存 c和python通信_c/c++_13