ios socket 实现简单的聊天系统

socket
  • socket又称套接字
  • 网络上的两个程序通过双向的通讯连接实现数据的交换, 这个连接的一端称为一个socket
  • 应用程序通过套接字向网络发出请求或者应答网络请求.
流程图

socket流程图.png
网络通讯的要素:
  • 网络上的请求就是通过socket来建立连接, 然后互相通讯
  • IP地址 (网络上主机设备的唯一标识)
  • 端口号(定位程序)
    • 用于标示进程的逻辑地址, 不同进程的标示
    • 有效端口: 0~65535, 其中0~1024由系统使用或者保留端口, 开发中建议使用1024以上的端口
  • 传输协议 (用什么样的方式进行交互)
    • 通讯的规则
    • 常见的协议: TCP, UDP

这里用xcode模拟服务端, 用命令行来模拟客户端, 进行交互

#import <Foundation/Foundation.h>
#import "GYServiceListener.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 1.创建一个服务监听对象
        GYServiceListener *listener = [[GYServiceListener alloc] init];
        // 2.开启监听
        [listener start];
        // 3.开启主运行循环, 让服务不能听, 否则命令行执行完就停止了
        [[NSRunLoop mainRunLoop] run];
    }
    return 0;
}
#import "GYServiceListener.h"
#import "GCDAsyncSocket.h"

@interface GYServiceListener () <GCDAsyncSocketDelegate>

@property (nonatomic, strong) GCDAsyncSocket *serverSocket;


@end


@implementation GYServiceListener


// 开启10086服务
- (void)start
{
    //1.创建一个socket对象 给他一个端口号5288
    //serverSocket 服务器端的socket只监听 有没有客户端的请求连接
    //在socket的代理方法中,可以监听到客户端的请求
    GCDAsyncSocket *serverSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];

    //2.绑定端口, 并开启监听, 下面这段代码也封装了开启监听, 代表10086服务已经开启
    NSError *error = nil;
    [serverSocket acceptOnPort:5288 error:&error];
    if (!error) {
        NSLog(@"10086服务开启成功");
    } else{
        // 失败的原因有可能是端口被其他程序占用了
        NSLog(@"10086服务开启失败 %@", error);
    }
    self.serverSocket = serverSocket;
}

/**
 *  有客户端的socket连接到服务器
 *  sock 服务端的socket
 *  newSocket 客户端连接过来的socket
 */
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{
    NSLog(@"serverSocket -- %@", sock);
    NSLog(@"clientSocket -- %@", newSocket);
}

打开用户偏好设置->网络->查看自己的ip地址


屏幕快照 2016-05-05 上午12.32.05.png


这时候我们在命令行中输入 $ telnet 127.0.0.1 5288
或者 $ telnet 192.168.0.100 5288
则就会调用上面的代理方法, 打印出serverSocket和clientSocket

因为有很多客户端连接到服务器, 所以我们定义一个数据保存所有的客户端socket, 根据流程图: 然后监听客户端有没有数据上传,读取数据,处理数据,写数据,回应数据

/**
 *  有客户端的socket连接到服务器
 *  sock 服务端的socket
 *  newSocket 客户端连接过来的socket
 */
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{
    NSLog(@"serverSocket -- %@", sock);
    NSLog(@"clientSocket -- %@", newSocket);
    // 1.保存客户端的socket
    [self.clientSockets addObject:newSocket];
    // 2.监听客户端有没有数据上传
    // 传递过来的客户端的socket来监听有没有数据上床
    // -1 代表不超时, tag标示作用,暂时用不到,写0
    // 如果有数据, 就会调用-socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag代理方法
    [newSocket readDataWithTimeout:-1 tag:0];

}
/**
 *  读取客户端请求的数据
 *  sock 客户端的socket
 */
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    // 1.读取数据
    NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"接受到客户端上传的数据 : %@", string);

    // 2.处理请求,写数据, 返回数据给客户端 (这里只是模拟,我只是让客户端给客户端发送来的数据,然后再给它传给客户端)
    [sock writeData:data withTimeout:-1 tag:0];

#warning 每次读取完数据后, 都要调用一次监听数据的方法, 否则只会接受一次数据
    [sock readDataWithTimeout:-1 tag:0];
}

我们来验证一下:
运行项目, 打开命令行, 输入一下命令:

命令行:(客户端)

重复的第二句 服务器端 返回的相同的数据


屏幕快照 2016-05-05 上午1.16.55.png
xcode:(服务器端)输出

屏幕快照 2016-05-05 上午1.19.47.png
模拟的服务器端所有代码:
#import "GYServiceListener.h"
#import "GCDAsyncSocket.h"

@interface GYServiceListener () <GCDAsyncSocketDelegate>

@property (nonatomic, strong) GCDAsyncSocket *serverSocket;

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

@end


@implementation GYServiceListener


- (NSMutableArray *)clientSockets
{
    if (!_clientSockets) {
        _clientSockets = [NSMutableArray array];
    }
    return _clientSockets;
}

// 开启10086服务
- (void)start
{
    //1.创建一个socket对象 给他一个端口号5288
    //serverSocket 服务器端的socket只监听 有没有客户端的请求连接
    //在socket的代理方法中,可以监听到客户端的请求
    GCDAsyncSocket *serverSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];

    //2.绑定端口, 并开启监听, 下面这段代码也封装了开启监听, 代表10086服务已经开启
    NSError *error = nil;
    [serverSocket acceptOnPort:5288 error:&error];
    if (!error) {
        NSLog(@"10086服务开启成功");
    } else{
        // 失败的原因有可能是端口被其他程序占用了
        NSLog(@"10086服务开启失败 %@", error);
    }
    self.serverSocket = serverSocket;
}

/**
 *  有客户端的socket连接到服务器
 *  sock 服务端的socket
 *  newSocket 客户端连接过来的socket
 */
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{
    NSLog(@"serverSocket -- %@", sock);
    NSLog(@"clientSocket -- %@", newSocket);
    // 1.保存客户端的socket
    [self.clientSockets addObject:newSocket];
    // 2.监听客户端有没有数据上传
    // 传递过来的客户端的socket来监听有没有数据上床
    // -1 代表不超时, tag标示作用,暂时用不到,写0
    // 如果有数据, 就会调用-socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag代理方法
    [newSocket readDataWithTimeout:-1 tag:0];

}
/**
 *  读取客户端请求的数据
 *  sock 客户端的socket
 */
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    // 1.读取数据
    NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"接受到客户端上传的数据 : %@", string);

    // 2.处理请求,写数据, 返回数据给客户端 (这里只是模拟,我只是让客户端给客户端发送来的数据,然后再给它传给客户端)
    [sock writeData:data withTimeout:-1 tag:0];

#warning 每次读取完数据后, 都要调用一次监听数据的方法, 否则只会接受一次数据
    [sock readDataWithTimeout:-1 tag:0];
}

@end


文/东方_未明(简书作者)
原文链接:http://www.jianshu.com/p/9cb60d675dc8
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
《网络程序设计》课程设计 基于socket聊天系统设计 摘要:本设计通过研究讨论,设计基于socket编程的网络聊天系统,服务器端采用多线程并发服务方式,多客户端能同时连接服务器,并且客户端之间能进行通信。程序通过了验证与测试,证明了系统的可用性、易用性、完善性。 关键词:socket、server、client、聊天系统 引言 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。一个聊天系统的通信模块就是Socket程序的设计与实现聊天系统分为服务器端和客户端,服务器端的任务就是接受客户端的不同请求,做出不同的响应,并处理多客户端之间的通信。 3.1头文件 /************************************************************ *chat.h * 基于socket聊天客户机和服务器的头文件 *设计思路: * 客户机提出各种请求,服务器根据不同请求,发送不同的响应. *关键问题: * 客户机和服务器之间协议制订 *************************************************************/ #include // for sockaddr_in #include // for socket #include // for socket #include // for printf #include // for exit #include // for bzero /************************************************************ *服务器端口定义 *************************************************************/ #define CHAT_SERVER_PORT (6666) /************************************************************ *报文类型定义 *************************************************************/ #define NO_COMMAND (100) //客户端发送报文类型 #define REGISTER (1) #define LOGIN (2) #define GET_USER_LIST (3) #define TALK_TO (4) #define EXIT (5) #define CHANGE (6) #define GET_MESSAGE (7) //服务器端发送报文类型

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值