Swift的socket通信调度

Swift的socket通信调度,swift,websocket,grand-central-dispatch,scheduling,Swift,Websocket,Grand Central Dispatch,Scheduling,我对Swift编程相当陌生,请原谅我下面要问的一些愚蠢的问题 在我的应用程序中,我试图安排调用一个函数,该函数将从我的服务器接收一些数据,并且每秒都会被调用。通信需要通过TCP套接字实现。在做了一些研究之后,我觉得我需要一种方法来正确使用线程来调用该函数。所以我的问题来了: 我应该在哪里连接到服务器?(我应该在我的第一个视图控制器的viewDidLoad()函数中建立连接吗?) 我应该在哪里创建线程来调度函数调用?如果我在第一个视图控制器内创建线程,那么在切换到另一个视图控制器后,线程是否会消亡

我对Swift编程相当陌生,请原谅我下面要问的一些愚蠢的问题

在我的应用程序中,我试图安排调用一个函数,该函数将从我的服务器接收一些数据,并且每秒都会被调用。通信需要通过TCP套接字实现。在做了一些研究之后,我觉得我需要一种方法来正确使用线程来调用该函数。所以我的问题来了:

  • 我应该在哪里连接到服务器?(我应该在我的第一个视图控制器的viewDidLoad()函数中建立连接吗?)
  • 我应该在哪里创建线程来调度函数调用?如果我在第一个视图控制器内创建线程,那么在切换到另一个视图控制器后,线程是否会消亡
  • 我应该为该线程使用什么QoS级别?该应用程序每秒呈现一次从服务器接收的数据,因此我假设此任务具有非常高的优先级
  • 我试图寻找有关线程和套接字通信的教程和示例,但找不到适用于我的应用程序的信息。因此,任何有关设计的帮助或见解都将不胜感激


    提前谢谢

    根据我的说法,可以对问题中提出的场景执行以下操作

  • 如果您要在启动应用程序后立即连接到服务器。我认为最好在
    AppDelegate
    中使用下面给出的选项完成启动

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    
    }
    
  • 这取决于您将如何切换到其他
    ViewController
    。在切换过程中,如果要取消分配当前的
    ViewController
    ,则线程将死亡

  • 考虑到您正在制作一个基于套接字的应用程序,并且每秒都会从服务器接收数据。那么,
    NSURLSession
    可能对您没有多大帮助。对于套接字通信,通常将使用
    NSInputStream
    NSOutputStream
    。objective-C中的以下示例可以帮助您开始:

     - (void)connectWithHostFromUrl: (NSURL *)hostUrl {
    
            CFReadStreamRef readStream;
            CFWriteStreamRef writeStream;
            CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)[hostUrl host], 80, &readStream, &writeStream);
    
           _inputStream = (__bridge_transfer NSInputStream *)readStream;
           [_inputStream setDelegate:self];
           [_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
           [_inputStream open];
    
           _outputStream = (__bridge_transfer NSOutputStream *)writeStream;
           [_outputStream setDelegate:self];
           [_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
           [_outputStream open];
      }
    
     // Delegate methods
    
    - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
    
            switch (eventCode) {
                 case NSStreamEventNone:
                 {
                  // handle it according to your need
                 }
                      break;
                 case NSStreamEventOpenCompleted:
                 {
                  // handle it according to your need
                 }
                      break;
                 case NSStreamEventHasBytesAvailable:
                 {
                     if (_receivedData == nil) {
                          _receivedData = [NSMutableData new];
                     }
                     uint8_t buffer[1024];
                     NSInputStream *inputStream = (NSInputStream *)aStream;
                     NSInteger bytesReceived = [inputStream read:buffer maxLength:1024];
                    if (bytesReceived > 0) {
                        [_receivedData appendBytes:(const void *)buffer length:bytesReceived];
                    }
                 }
                      break;
                 case NSStreamEventHasSpaceAvailable:
                 {
                      if (_dataToSend != nil) {
                        // _dataToSend is NSMutableData/NSData object
                          NSOutputStream *outputStream = (NSOutputStream *)aStream;
                          const uint8_t *mutableBytes = (const uint8_t *)[_dataToSend mutableBytes];
                          NSInteger length = [_dataToSend length]/sizeof(uint8_t);
                          [outputStream write:(const uint8_t *)mutableBytes maxLength:length];
                      }
                  }
                      break;
                  case NSStreamEventErrorOccurred:
                  {
                    // handle it according to your need
                  }
                      break;
                  case NSStreamEventEndEncountered:
                  {
                    // handle it according to your need
                  }
                      break;
                  default:
                      break;
           }
    }
    
  • 因为这里有很多案子要处理。大多数情况下,我建议使用经过测试的第三方库,如


    请建议编辑以更好地回答这个问题:)

    经过一些挖掘,我找到了在Swift端实现流编程的方法(使用本机Swift功能)。事实证明,Swift中的方式与Objective C中的方式非常相似

    在Swift中启用流编程所需的两个函数是
    func connect()
    ,这是我自己编写的,和
    func stream(\uastream:stream,handle eventCode:stream.Event)
    ,这是作为
    StreamDelegate
    中的方法提供的

    以下是
    func connect()
    的外观:

    func connect() {
        Stream.getStreamsToHost(withName: <serverIP>, port: <serverPort>, inputStream: &inputStream, outputStream: &)
    
        guard let inputStream = inputStream, let outputStream = outputStream else {
            print(" ->\tNetworkControllerError: Cannot open inputstream/outputstream.")
            return
        }
    
        // Set delegate
        inputStream.delegate = self
        outputStream.delegate = self
    
        let socketWorkQueue = DispatchQueue(label: "socketWorkQueue", attributes: .concurrent)
        CFReadStreamSetDispatchQueue(inputStream, socketWorkQueue)
        CFWriteStreamSetDispatchQueue(outputStream, socketWorkQueue)
    
        inputStream.open()
        outputStream.open()
    }
    
    func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
    
        if aStream === inputStream {
            switch eventCode {
            case Stream.Event.errorOccurred:
                streamEventQueue.async {
                    // do something here
                }
                break
            case Stream.Event.openCompleted:
                streamEventQueue.async {
                    // do something here
                }
                break
            case Stream.Event.hasBytesAvailable:
                streamEventQueue.async {
                    // do something here
                    let output = read()
                }
                break
            case Stream.Event.endEncountered:
                streamEventQueue.async {
                    // do something here
                }
                break
            default:
                break
            }
        }
        else if aStream === outputStream {
            switch eventCode {
            case Stream.Event.errorOccurred:
                streamEventQueue.async {
                    // do something here
                }
                break
            case Stream.Event.openCompleted:
                streamEventQueue.async {
                    // do something here
                }
                break
            default:
                break
            }
        }
    }
    
    因此,
    stream()
    函数应该是我的应用程序中处理由网络连接/断开引起的状态转换的唯一地方。注意,我还使用了一个串行事件队列来处理流事件。这是为了防止任何可能导致国家腐败的潜在种族状况


    对于那些不太熟悉流编程的人来说,这是一种服务器-客户机通信模式,它使连接/套接字保持活动状态。连接需要保持活动状态,这主要是因为服务器和客户端之间存在持续的通信。像RESTful API这样的通信模式会因客户端的请求而给服务器带来很大的负担,因此不推荐使用。

    您是打算每次都建立一个新连接还是保持一个持久连接?您是否研究过NSURLSession中的内置API以了解它们是否满足您的需求?@jtbandes感谢您的及时回复。我需要保持应用程序的持久TCP连接。我还研究了NSURLSession,但这个API似乎更适合HTTP RESTful支持(我非常高兴被纠正)。在我的情况下,不断地对服务器进行新的REST调用会给服务器带来巨大的负担。