socket
- socket又称套接字
- 网络上的两个程序通过
双向的通讯连接实现数据的交换
, 这个连接的一端称为一个socket - 应用程序通过
套接字
向网络发出请求或者应答网络请求.
流程图
网络通讯的要素:
- 网络上的请求就是通过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地址
这时候我们在命令行中输入 $ 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];
}
我们来验证一下:
运行项目, 打开命令行, 输入一下命令:
命令行:(客户端)
重复的第二句 服务器端 返回的相同的数据
xcode:(服务器端)输出
模拟的服务器端所有代码:
#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
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
原文链接:http://www.jianshu.com/p/9cb60d675dc8
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。