利用Socket模拟10086服务器读写数据

前言

  • 如果想要更加轻松愉悦的深入学习XMPP,必须要从最简单的开始,学习是一个循序渐进的过程,只有清楚各个组成部分的工作原理,我们才能更好的学习更加深层的知识.今天我们来学习一下XMPP中的Socket.
  • 本章整体结构 : 利用一个第三方框架,快速上手Socket,我们就通过模拟一下10086服务器的读写功能,从而侧面了解什么事Scoket.

步骤 :

  • 1, 导入第三方框架GCDAsyncSocket,注意,我们在github上下载该框架时,我们使用的是source里面的TCP类型的框架,在source中有两种类型的头文件,一种是TCP类型,另一种是UDP类型.
  • 2, 新建一个对象方法,用于监听10086的服务器是否开启
#import <Foundation/Foundation.h>

@interface WGServicerListener : NSObject

/** 定义一个对象方法,用于开启10086服务器 */
- (void)start;

@end

  • 3, 来到main.m文件中,监听服务器是否需要开启
#import <Foundation/Foundation.h>
#import "WGServicerListener.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        // 创建监听100086服务器的对象,只要连接到IP地址,就开启10086服务器
        WGServicerListener *listener = [[WGServicerListener alloc] init];

        // 开启服务器
        [listener start];

        // 保证开启服务器以后,一直处于开启状态
        [[NSRunLoop mainRunLoop] run];

        // 小常识 : 服务器是不会停的(所以, 需要手动开启一个主运行循环)
    }
    return 0;
}

  • 4, 实现开启服务器的方法

#import "WGServicerListener.h"
#import "GCDAsyncSocket.h"

@interface WGServicerListener ()<GCDAsyncSocketDelegate>

// 服务器Soket
@property(nonatomic, strong) GCDAsyncSocket *serverSocket;

// 保存客户端所有的Socket对象
@property(nonatomic, strong) NSMutableArray *clientSockets;

@end

@implementation WGServicerListener

#pragma mark -  懒加载
- (NSMutableArray *)clientSockets
{
    if (_clientSockets == nil) {

        _clientSockets = [NSMutableArray array];
    }
    return _clientSockets;
}

- (void)start {

    // 1, 创建服务器的socket对象,serverSocket只会监听有没有客户端请求连接
    GCDAsyncSocket *serverSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];

    // 2, 绑定和监听客户端的连接
    NSError *error = nil;
    [serverSocket acceptOnPort:1688 error:&error];

    // 判断error是否有值,如果有值表示开启失败
    if (!error) {

        // 开启成功
        NSLog(@"10086服务器已开启");
    } else
    {
    // 开启失败
        NSLog(@"10086服务器开启失败 : %@",error);
    }

    // 保存服务器的Socket对象
    self.serverSocket = serverSocket;
}
  • 注意 :

  • 1,导入第三方框架时,最好编译一下,判断有没有存在依赖的框架.

  • 2, 定义了两个属性,一个是服务器的Socket对象,另一个是保存所有连接上来的客户端Socket对象(它需要懒加载,因为连接上来的客户端不止一个,所以需要懒加载,用到时才加载).

  • 3, 端口号1688是随便写的,只要是大于1024小于65535即可,但是, 有可能连接有问题,或者连接失败,原因是可能端口号已被占用.

  • 5, 开启服务器之后,需要监听服务器是否有和客户端连接

// 需要监听服务器是否有连接到新的客户端,所以, 监听方法是属于协议中的方法,要遵守协议

/**
 * 只要有新的端口和服务器连接就会调用该方法.
 * 前面个sock是服务器的端口, 后面个newSocket是客户端的端口,可以自定义参数名
 */
- (void)socket:(GCDAsyncSocket *)serverSocket didAcceptNewSocket:(GCDAsyncSocket *)clientSocket
{

    // 将连接进来的客户端的Socket对象保存到数组中
    [self.clientSockets addObject:clientSocket];

    // 只要开启服务就提示用户有什么类型的服务
    NSMutableString *promptStr = [NSMutableString string];
    [promptStr appendString:@"欢迎来到10086在线服务,请输入下面的数字选择服务\n"];
    [promptStr appendString:@"[0]在线充值\n"];
    [promptStr appendString:@"[1]在线投诉\n"];
    [promptStr appendString:@"[2]优惠信息\n"];
    [promptStr appendString:@"[3]special services\n"];
    [promptStr appendString:@"[4]退出\n"];

    // 客户端写入数据
    [clientSocket writeData:[promptStr dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];

    // 监听客户端有没有上传数据
    [clientSocket readDataWithTimeout:-1 tag:0];
}
  • 注意 :

  • 1, 只要是有新的客户端与服务器连接就一定会来到这个方法.

  • 2, 值得注意的是,客户端clientSocket对象并不是和服务器的serverSocket对应的,换句话说,服务器读取客户端上传的数据时并不是serverSocket,而是服务器中的clientSocket对象来读取的(这样说有点抽象,具体看下面的图).

  • 6, 的那个客户端上传数据之后,服务器需要做相应的响应

/**
 * 监听客户端有没有输入数据,只要客户端上传了数据,那么就一定会调用下面这个方法
 *
 */
- (void)socket:(GCDAsyncSocket *)clientSocket didReadData:(NSData *)data withTag:(long)tag
{

    NSLog(@"客户端输入数据了");  // 测试用

    // 此时,服务器接收到的是一个NSData,我们需要将NSData转为一个字符串
    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    // 将字符串转为数字,使用switch输出对应的字符串
    NSInteger number = [str integerValue];
    NSString *responseStr = nil;
    switch (number) {
        case 0:
            responseStr = @"充值服务进行中...\n";
            break;
        case 1:
            responseStr = @"10086的投诉服务几乎零处理...\n";
            break;
        case 2:
            responseStr = @"几乎所有优惠信息都是骗人的...\n";
            break;
        case 3:
            responseStr = @"特殊服务倒是做的勤快...\n";
            break;
        case 4:
            responseStr = @"您已经退出了,并且扣了50块钱\n";
            break;
        default:

            break;
    }

    // 服务器读取客户端上传的数据
    [clientSocket writeData:[responseStr dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];

    // 当number = 4 说明用户需要退出,但是我们需要将客户端和服务器之间的连接断开
    if (number == 4) {

        // 将数组中的客户端全部移除掉
        [self.clientSockets removeObject: clientSocket];
    }

    // 只要客户端上传1次数据,服务器都需要监听它
    [clientSocket readDataWithTimeout:-1 tag:0];
}
  • 注意 :

  • 1, 这个方法的调用时刻 : 只要客户端上传数据,就会调用该方法

  • 2, 传进来的一个NSData类型,需要转出字符串,需要理解是怎么转变的

  • 3, 字符串是如何转变为整型的

  • 4, 如何将服务器和客户端断开连接

  • 5, 注意最后一行代码,它表示的意思是只要客户端上传数据,它都去读取,如果不写最后一句,不管客户端输入什么,服务器都不会做出任何反应.

  • 终端图片表示运行结果.



    {}.png
  • Scoket的通信流程图


    Socket通信流程图.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容