OSI:?
開放系統(tǒng)互連參考模型 (Open System Interconnect 簡稱OSI)是國際標準化組織(ISO)和國際電報電話咨詢委員會(CCITT)聯(lián)合制定的開放系統(tǒng)互連參考模型,為開放式互連信息系統(tǒng)提供了一種功能結(jié)構(gòu)的框架。它從低到高分別是:物理層、數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層、會話層、表示層和應用層。
物理層:物理層并不是物理媒體本身,它只是開放系統(tǒng)中利用物理媒體實現(xiàn)物理連接的功能描述和執(zhí)行連接的規(guī)程。物理層提供用于建立、保持和斷開物理連接的機械的、電氣的、功能的和過程的條件。簡而言之,物理層提供有關(guān)同步和全雙工比特流在物理媒體上的傳輸手段,其典型的協(xié)議有RS 232C、RS 449/422/423、V.24和X.21、X.21bis等。
端口號:每一個應用程序有很多的服務!每一個服務對應著一個端口號。
數(shù)據(jù)鏈路層:數(shù)據(jù)鏈路可以粗略地理解為數(shù)據(jù)通道。物理層要為終端設(shè)備間的數(shù)據(jù)通信提供傳輸介質(zhì)及其連接。
網(wǎng)絡(luò)層:選擇最優(yōu)路徑
// 客戶端socket
#import "ViewController.h"
#import "GCDAsyncSocket.h"
@interface ViewController ()
@property(nonatomic,strong)GCDAsyncSocket *clientSocket;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.clientSocket connectToHost:@"127.0.0.1" onPort:1234 error:NULL];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark GCDAsyncSocketDelegate
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{
NSLog(@"已經(jīng)連接成功后調(diào)用");
[self.clientSocket readDataWithTimeout:-1 tag:0];
}
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
// 發(fā)送數(shù)據(jù)
NSString *str = @"你好,服務器!";
[self.clientSocket writeData:[str dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
// 接收數(shù)據(jù)
[self.clientSocket readDataWithTimeout:-1 tag:0];
}
#pragma mark 懶加載
-(GCDAsyncSocket *)clientSocket{
if (_clientSocket == nil) {
_clientSocket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue() socketQueue:NULL];
}
return _clientSocket;
}
@end
// 服務端
#import "ViewController.h"
#import "GCDAsyncSocket.h"
@interface ViewController ()// 用于監(jiān)聽的socket
@property(nonatomic,strong)GCDAsyncSocket *listenSocket;
// 保存用于數(shù)據(jù)交互的socket (需要強引用 但是如果群聊需要多個強引用 所以建立數(shù)組)
@property(nonatomic,strong)NSMutableArray *connectedSockets;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)setRepresentedObject:(id)representedObject {
[super setRepresentedObject:representedObject];
// Update the view, if already loaded.
}
- (IBAction)clickStartServer:(id)sender {
// 綁定ip&監(jiān)聽端口&接收新連接封裝在一個方法中
BOOL success = [self.listenSocket acceptOnInterface:@"127.0.0.1" port:1234 error:nil];
if (success) {
NSLog(@"服務器開啟成功");
}else{
NSLog(@"服務器開啟失敗");
}
}
#pragma mark GCDAsyncSocketDelegate
/**
*? 已經(jīng)接收到新的連接后調(diào)用
*
*? @param sock? ? ? 服務端用于監(jiān)聽的socket
*? @param newSocket 服務端用于數(shù)據(jù)交互的socket
*/
-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket{
NSLog(@"接收到來自%@的連接,其端口為%hu",newSocket.connectedHost,newSocket.connectedPort);
[self.connectedSockets addObject:newSocket];
// 設(shè)置歡迎信息
NSString *str = [NSString stringWithFormat:@"歡迎連接我的MAC服務器"];
[newSocket writeData:[str dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
//? ? // 定時器 輪詢
//? ? [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(readData:) userInfo:newSocket repeats:YES];
//? ? // 開啟異步線程runloop(因為接收socket為異步不會執(zhí)行 NSTimer)
//? ? [[NSRunLoop currentRunLoop]run];
// 接收數(shù)據(jù)
[newSocket readDataWithTimeout:-1 tag:0];
}
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
NSLog(@"已經(jīng)發(fā)送出去");
}
//-(void)readData:(NSTimer *)obj{
//? ? // 接收數(shù)據(jù)
//? ? GCDAsyncSocket *socket = obj.userInfo;
//? ? [socket readDataWithTimeout:-1 tag:0];
//}
/**
*? 已經(jīng)接收到的數(shù)據(jù)
*
*? @param sock 服務端用于數(shù)據(jù)交互的socket
*? @param data 接收到的數(shù)據(jù)
*? @param tag? 標記
*/
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
// 接收的數(shù)據(jù)
[sock readDataWithTimeout:-1 tag:0];
// 轉(zhuǎn)發(fā)給指定用戶
for (GCDAsyncSocket *connetctedSocket in self.connectedSockets) {
if (connetctedSocket != sock) {
[connetctedSocket writeData:data withTimeout:-1 tag:0];
}
}
}
#pragma mark? 懶加載
-(GCDAsyncSocket *)listenSocket{
if (_listenSocket == nil) {
_listenSocket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0) socketQueue:NULL];
}
return _listenSocket;
}
-(NSMutableArray *)connectedSockets{
if (_connectedSockets == nil) {
_connectedSockets = [NSMutableArray array];
}
return _connectedSockets;
}
@end