zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    第一次作业
    Zotero引用文献格式(软件学报)
    好文索引
    【思维导图】分享以前整理的两张思维导图吧
    Nokia N9开启开发者模式
    Windows10 Ubuntu子系统折腾
    [CSAPP]并发与并行
    [读书笔记]逻辑思维,只要五步
    linux配置备忘
    从现在就开始写博客
  • 原文地址:https://www.cnblogs.com/huen/p/3713843.html
Copyright © 2011-2022 走看看