一、 Socket介绍
来由:多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。
Socket又称为“套接字”,是系统提供的用于网络通信的方法。Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。
建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket,另一个运行于服务器端,称为ServerSocket。套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接,UDP连接同理。
二、Socket、TCP/IP和Http的联系和区别
HTTP协议是基于TCP连接的。
TCP/IP是传输层协议,主要解决数据如何在网络中传输;
而HTTP是应用层协议,主要解决如何包装数据。
在传输数据时候可以只是用TCP/IP,但是这样没有应用层,无法识别传输的数据类容,这样是没有意义的,如果想使传输的数据有意义,则必须使用应用层协议,HTTP就是一种,WEB使用它封装HTTP文本信息,然后使用TCP/IP协议传输到网络上。
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,是它的一组接口。通过Socket,我们才能使用TCP/IP协议。
Socket和HTTP还有一个区别是Socket一旦建立连接,服务器可以主动将数据传输给客户端;而HTTP则需要客户端先向服务器发送请求之后才能将数据返回给客户端。但实际上Socket建立之后因为种种原因,会导致断开连接,其中一个原因就是防火墙会断开长时间处于非活跃状态的连接,因此需要轮询高速网络,这个连接是活跃的。
(附1:网络七层协议由下往上分别为物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。其中物理层、数据链路层和网络层通常被称作媒体层,是网络工程师所研究的对象;传输层、会话层、表示层和应用层则被称作主机层,是用户所面向和关心的内容。)
(附2:TCP/IP五层模型的协议分为:应用层、传输层、网络层、数据链路层和物理层)
三、Socket在iOS中的使用
- 第三方AsyncSockets的使用
#import <Foundation/Foundation.h>
#import "AsyncSocket.h"
enum{
SocketOfflineByServer,
SocketOfflineByUser,
};
@interface SocketSingleton : NSObject<AsyncSocketDelegate>
@property (nonatomic, strong) AsyncSocket *socket; // socket
@property (nonatomic, copy ) NSString *socketHost; // socket的Host
@property (nonatomic, assign) UInt16 socketPort; // socket的prot
@property (nonatomic, retain) NSTimer *connectTimer; // 计时器
+ (SocketSingleton *)sharedInstance;
-(void)socketConnectHost;// socket连接
-(void)cutOffSocket;// 断开socket连接
-(void)socketSendData:(NSData *) data;// socket发送数据
@end
#import "SocketSingleton.h"
@implementation SocketSingleton
+(SocketSingleton *) sharedInstance {
static SocketSingleton *sharedInstace = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstace = [[self alloc] init];
});
return sharedInstace;
}
// socket连接
-(void)socketConnectHost {
self.socket = [[AsyncSocket alloc] initWithDelegate:self];
NSError *error = nil;
BOOL isConnect = [self.socket connectToHost:self.socketHost onPort:self.socketPort withTimeout:-1 error:&error];;
if (isConnect) {
NSLog(@"socket连接成功");
}else {
NSLog(@"socket连接失败");
}
}
// socket发送数据
-(void)socketSendData:(NSData *) data {
[self.socket writeData:data withTimeout:-1 tag:1];//-1不设置超时
}
// 连接成功回调
-(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port {
NSLog(@"socket连接成功");
[self.socket readDataWithTimeout: -1 tag: 0];
self.connectTimer = [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(longConnectToSocket) userInfo:nil repeats:YES];
[self.connectTimer fire];
}
// 心跳连接
-(void)longConnectToSocket{
// 根据服务器要求发送固定格式的数据,假设为指令@"longConnect",但是一般不会是这么简单的指令
NSData *dataStream = [@"longConnect" dataUsingEncoding:NSUTF8StringEncoding];
[self.socket writeData:dataStream withTimeout:-1 tag:1];//-1不设置超时
}
-(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSString *msg = [[NSString alloc] initWithData: data encoding:NSUTF8StringEncoding];
NSDictionary *dic = @{@"message":msg};
[[NSNotificationCenter defaultCenter] postNotificationName:@"SOCKETREAGSUCCESS" object:nil userInfo:dic];
[self.socket readDataWithTimeout: -1 tag: 0];
}
-(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag{
// [self addMessage:[NSString stringWithFormat:@"发送了"]];
}
-(void)onSocketDidDisconnect:(AsyncSocket *)sock{
NSLog(@"socket断开连接 %ld",sock.userData);
if (sock.userData == SocketOfflineByServer) {
// 服务器掉线,重连
[self socketConnectHost];
}else if (sock.userData == SocketOfflineByUser) {
// 如果由用户断开,不进行重连
return;
}
}
// 切断socket
-(void)cutOffSocket{
self.socket.userData = SocketOfflineByUser;
[self.connectTimer invalidate];
[self.socket disconnect];
}
@end
- 用C语言实现Socket
1、Socket调用库函数主要有:
创建套接字
Socket(af,type,protocol)
建立地址和套接字的联系
bind(sockid, local addr, addrlen)
服务器端侦听客户端的请求
listen( Sockid ,quenlen)
建立服务器/客户端的连接 (面向连接TCP)
客户端请求连接
Connect(sockid, destaddr, addrlen)
服务器端等待从编号为Sockid的Socket上接收客户连接请求
newsockid=accept(Sockid,Clientaddr, paddrlen)
发送/接收数据
面向连接:
send(sockid, buff, bufflen)
面向无连接:
sendto(sockid,buff,…,addrlen)
recvfrom( )
释放套接字
close(sockid)
四、其他
iOS中Socket编程的方式:
BSD Socket:
BSD Socket 是UNIX系统中通用的网络接口,它不仅支持各种不同的网络类型,而且也是一种内部进程之间的通信机制。而iOS系统其实本质就是UNIX,所以可以用,但是比较复杂。
CFSocket:
CFSocket是苹果提供给我们的使用Socket的方式。
AsyncSocket:
第三方开源库,首选方式,也是在开发项目中经常会用到的。
以后有机会慢慢学习。
参考文章:iOS学习之Socket使用简明教程- AsyncSocket
项目地址: SocketDemo