Scoket

流程:

服务器:                      客户端:

监听端口,等待访问                   指定服务器ip、端口、传输协议

    ↓                            ↓

                                                              请求

           ←-----------------------------

                               -----------------------------→

           响应并建立连接

    ↓                            ↓

                                             IO传输

                              <------------------------------>


    ↓                            ↓

 关闭socket,释放资源                 关闭socket,释放资源

           


 2.Peer To Peer 点对点通信(蓝牙)


服务器端

 .h

#import <Foundation/Foundation.h>
#import <netinet/in.h>
#import <sys/socket.h>
@interface Server : NSObject<NSNetServiceDelegate>


@property(nonatomic,strong)NSNetService *service;
@property(nonatomic,strong)NSSocketPort *socket;

@property(nonatomic,strong)NSInputStream *inputStream;
@property(nonatomic,strong)NSOutputStream *outputStream;

@property(nonatomic,assign)int port;

@end

.m

#import "Server.h"

/* 服务器接收到客户端请求后回调,它是CFSocketCallBack类型 */
void AcceptCallBack(CFSocketRef socket,CFSocketCallBackType type,CFDataRef address,const void *data,void *info);

/* 客户端在socket中读取数据时调用 */
void WriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType eventType,void *clientCallBackInfo);

/* 客户端把数据写入socket时调用 */
void ReadStreamClientCallBack(CFReadStreamRef stream,CFStreamEventType eventType, void *clientCallBackInfo);

@implementation Server

-(id)init{
    if (self = [super init]) {
        if ([self startServer]) {
            [self publishService];
        }else{
            NSLog(@"启动服务器失败");
        }
    }
    return self;
}

-(BOOL)startServer{
    /*定义一个server socket引用*/
    CFSocketRef sserver;
    
    //创建socket context
    CFSocketContext ctx = {0,(__bridge void *)(self),NULL,NULL,NULL};
    
    //创建server socket TCP IPv4设置回调函数
    sserver = CFSocketCreate(NULL, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, (CFSocketCallBack)AcceptCallBack, &ctx);
    if (sserver == NULL) {
        return NO;
    }
    
    //设置是否重新绑定标志
    int yes = 1;
    //设置socket的属性 SOL_SOCKET设置tcp SO_REUSEADDR是重新绑定 yes 是否重新绑定
    setsockopt(CFSocketGetNative(sserver), SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
    
    
    //设置端口和地址
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr)); //memset函数对指定的地址进行内存复制
    addr.sin_len = sizeof(addr);
    addr.sin_family = AF_INET; //设置ipv4
    addr.sin_port = 0; //表示动态分配端口
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    
    //从指定字节缓冲区复制,一个不可变的CFData对象
    CFDataRef address = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&addr, sizeof(addr));
    
    //设置socket
    if (CFSocketSetAddress(sserver, (CFDataRef)address) != kCFSocketSuccess) {
        fprintf(stderr, "socket绑定失败!
");
        CFRelease(sserver);
        return NO;
        
    }
    
    //通过 Bonjour广播服务器时使用
    NSData *socketAddressActualData = (__bridge NSData *)(CFSocketCopyAddress(sserver));
    
    //转换 socket_in -> socketAddressActual
    struct sockaddr_in socketAddressActual;
    memcpy(&socketAddressActual, [socketAddressActualData bytes], [socketAddressActualData length]);
    
    self.port = ntohs(socketAddressActual.sin_port);
    
    printf("socket listening on port %d
",self.port);
    
    
    //创建一个RunLoop socket源
    CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sserver, 0);
    //socket源添加到RunLoop中
    CFRunLoopAddSource(CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes);
    CFRelease(sourceRef);
    return YES;
    
}

-(BOOL)publishService{
    _service = [[NSNetService alloc] initWithDomain:@"local." type:@"_tonyipp._tcp" name:@"tony" port:self.port];
    
    //添加服务到当前的RunLoop
    [_service scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
    [_service setDelegate:self];
    [_service publish];
    return YES;
}




void AcceptCallBack(CFSocketRef socket,CFSocketCallBackType type,CFDataRef address,const void *data,void *info){
    CFReadStreamRef readStream = NULL;
    CFWriteStreamRef writeStream = NULL;
    
    //data 参数含义是,如果回调类型是kCFSocketAcceptCallBack,data就是CFSocketNativeHandle类型指针
    CFSocketNativeHandle sock = *(CFSocketNativeHandle *)data;
    
    //创建读写Socket流
    CFStreamCreatePairWithSocket(kCFAllocatorDefault, sock, &readStream, &writeStream);
    
    if (!readStream || !writeStream) {
        close(sock);
        fprintf(stderr, "创建读写Socket流失败!!!
");
        return;
    }
    
    CFStreamClientContext streamText = {0,NULL,NULL,NULL,NULL};
    
    //注册两种回调函数
    CFReadStreamSetClient(readStream, kCFStreamEventHasBytesAvailable, ReadStreamClientCallBack, &streamText);
    
    CFWriteStreamSetClient(writeStream, kCFStreamEventCanAcceptBytes, WriteStreamClientCallBack, &streamText);
    
    //加入到循环中
    CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    CFWriteStreamScheduleWithRunLoop(writeStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    
    
    CFReadStreamOpen(readStream);
    CFWriteStreamOpen(writeStream);
    
    
    
}


void ReadStreamClientCallBack(CFReadStreamRef stream,CFStreamEventType eventType, void *clientCallBackInfo){
    uint8 buff[255];
    CFReadStreamRef inputStream = stream;
    
    if (NULL != inputStream) {
        CFReadStreamRead(stream, buff, 255);
        printf("接收数据:%s
",buff);
        CFReadStreamUnscheduleFromRunLoop(inputStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
        inputStream = NULL;
    }
}

void WriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType eventType,void *clientCallBackInfo){
    
    CFWriteStreamRef outputStream = stream;
    //输出
    UInt8 buff[] = "您好,我能够使用Socket了,哈哈哈";
    
    if (NULL != outputStream) {
        CFWriteStreamWrite(outputStream, buff, strlen((const char *)buff)+1);
        CFWriteStreamClose(outputStream);
        CFWriteStreamUnscheduleFromRunLoop(outputStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
        outputStream = NULL;
        
    }
    
}




#pragma mark -NetServiceDelegate-

-(void)netServiceDidPublish:(NSNetService *)sender{
    NSLog(@"netServiceDidPublish");
    
    if ([@"tony" isEqualToString:sender.name]) {
        if (![sender getInputStream:&_inputStream outputStream:&_outputStream]) {
            NSLog(@"连接服务器失败");
            return;
        }
    }
    
}


@end

客户端

.h

#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 49302
@interface MViewController : UIViewController<NSStreamDelegate>{
    int flag;//操作标志 0为发送 1为接收
}
@property (weak, nonatomic) IBOutlet UIButton *sendBtn;
@property (weak, nonatomic) IBOutlet UIButton *acceptBtn;
@property (weak, nonatomic) IBOutlet UILabel *messageLabel;

@property(nonatomic,retain)NSInputStream *inputStream;
@property(nonatomic,retain)NSOutputStream *outputStream;

-(IBAction)sendData:(id)sender;
-(IBAction)receiveData:(id)sender;
@end

.m

#import "MViewController.h"

@interface MViewController ()

-(void)initNetworkCommunication;

@end

@implementation MViewController



- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
}

-(void)initNetworkCommunication{
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;
    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"192.168.1.24", PORT, &readStream, &writeStream);
    
    _inputStream = (__bridge_transfer NSInputStream *)readStream;
    _outputStream = (__bridge_transfer NSOutputStream *)writeStream;
    [_inputStream setDelegate:self];
    [_outputStream setDelegate:self];
    
    [_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    
    [_inputStream open];
    [_outputStream open];
    

    
    
}


-(IBAction)sendData:(id)sender{
    flag = 0;
    [self initNetworkCommunication];
}
-(IBAction)receiveData:(id)sender{
    flag = 1;
    [self initNetworkCommunication];
}


#pragma mark delegate

-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{
    NSString *event;
    switch (eventCode) {
        case NSStreamEventNone:
        {
            event = @"None";
        }
            break;
        case NSStreamEventOpenCompleted:
        {
            event = @"OpenCompleted";
        }
            break;
        case NSStreamEventHasBytesAvailable:
        {
            event = @"HasBytesAvailable";
            if (flag == 1 && aStream == _inputStream) {
                NSMutableData *input = [[NSMutableData alloc] init];
                uint8_t buffer[1024];
                int len;
                while ([_inputStream hasBytesAvailable]) {
                    len = [_inputStream read:buffer maxLength:sizeof(buffer)];
                    if (len > 0) {
                        [input appendBytes:buffer length:len];
                    }
                }
                NSString *resultString = [[NSString alloc] initWithData:input encoding:4];
                _messageLabel.text = resultString;
            }
        }
            break;
        case NSStreamEventHasSpaceAvailable:
        {
            event = @"HasSpaceAvailable";
            if (flag == 0 && aStream == _outputStream) {
                //输出
                UInt8 buff[] = "您好,能收到我的信息么?";
                [_outputStream write:buff maxLength:strlen((const char *)buff) +1];
                [_outputStream close];
                
            }
            
        }
            break;
        case NSStreamEventErrorOccurred:
        {
            [self close];
        }
            break;
        case NSStreamEventEndEncountered:
        {
            [self close];
        }
            break;
        default:
        {
            [self close];
        }
            break;
    }
}

-(void)close{
    [_outputStream close];
    [_outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [_outputStream setDelegate:nil];
    [_inputStream close];
    [_inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [_inputStream setDelegate:nil];
}





@end
原文地址:https://www.cnblogs.com/huen/p/3713843.html