16

有谁知道 iOS 设备的简单 TCP 示例,所以我可以将字符串发送到服务器。我查看了以下库https://github.com/robbiehanson/CocoaAsyncSocket,但它似乎非常冗长。

我真正想要的只是有一种简单的方法来连接到 IP 地址和端口号并将一串数据发送到该地址。有谁知道一个简单的方法来做到这一点?

4

7 回答 7

28

SocketConnectionVC.h

#import <UIKit/UIKit.h>

@interface SocketConnectionVC : UIViewController<NSStreamDelegate>
{
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;

    NSInputStream   *inputStream;
    NSOutputStream  *outputStream;

    NSMutableArray  *messages;
}

@property (weak, nonatomic) IBOutlet UITextField *ipAddressText;
@property (weak, nonatomic) IBOutlet UITextField *portText;
@property (weak, nonatomic) IBOutlet UITextField *dataToSendText;
@property (weak, nonatomic) IBOutlet UITextView *dataRecievedTextView;
@property (weak, nonatomic) IBOutlet UILabel *connectedLabel;


@end

套接字连接VC.m

#import "SocketConnectionVC.h"

@interface SocketConnectionVC ()

@end

@implementation SocketConnectionVC

- (void)viewDidLoad {
    [super viewDidLoad];

    _connectedLabel.text = @"Disconnected";
}

- (IBAction) sendMessage {

    NSString *response  = [NSString stringWithFormat:@"msg:%@", _dataToSendText.text];
    NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
    [outputStream write:[data bytes] maxLength:[data length]];

}

- (void) messageReceived:(NSString *)message {

    [messages addObject:message];

    _dataRecievedTextView.text = message;
    NSLog(@"%@", message);
}

- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {

    NSLog(@"stream event %lu", streamEvent);

    switch (streamEvent) {

        case NSStreamEventOpenCompleted:
            NSLog(@"Stream opened");
            _connectedLabel.text = @"Connected";
            break;
        case NSStreamEventHasBytesAvailable:

            if (theStream == inputStream)
            {
                uint8_t buffer[1024];
                NSInteger len;

                while ([inputStream hasBytesAvailable])
                {
                    len = [inputStream read:buffer maxLength:sizeof(buffer)];
                    if (len > 0)
                    {
                        NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];

                        if (nil != output)
                        {
                            NSLog(@"server said: %@", output);
                            [self messageReceived:output];
                        }
                    }
                }
            }
            break;

        case NSStreamEventHasSpaceAvailable:
            NSLog(@"Stream has space available now");
            break;

        case NSStreamEventErrorOccurred:
             NSLog(@"%@",[theStream streamError].localizedDescription);
            break;

        case NSStreamEventEndEncountered:

            [theStream close];
            [theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            _connectedLabel.text = @"Disconnected";
            NSLog(@"close stream");
            break;
        default:
            NSLog(@"Unknown event");
    }

}

- (IBAction)connectToServer:(id)sender {

    NSLog(@"Setting up connection to %@ : %i", _ipAddressText.text, [_portText.text intValue]);
    CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef) _ipAddressText.text, [_portText.text intValue], &readStream, &writeStream);

    messages = [[NSMutableArray alloc] init];

    [self open];
}

- (IBAction)disconnect:(id)sender {

    [self close];
}

- (void)open {

    NSLog(@"Opening streams.");

    outputStream = (__bridge NSOutputStream *)writeStream;
    inputStream = (__bridge NSInputStream *)readStream;

    [outputStream setDelegate:self];
    [inputStream setDelegate:self];

    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

    [outputStream open];
    [inputStream open];

    _connectedLabel.text = @"Connected";
}

- (void)close {
    NSLog(@"Closing streams.");
    [inputStream close];
    [outputStream close];
    [inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [inputStream setDelegate:nil];
    [outputStream setDelegate:nil];
    inputStream = nil;
    outputStream = nil;

    _connectedLabel.text = @"Disconnected";
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

此 SocketConnectionVC 的 ui 快照 在此处输入图像描述

并按照以下步骤

1- input the ip on ipAdress textfield
2- input the port on port textfield
3- press connect button
4- (make sure the ip address and port is correct and the open of stream is fine. you can show the status of stream on console of Xcode)
5- input data to send to server
6- press send button
7- you can show the received message from server on the text view above connect button
于 2015-10-30T15:03:40.830 回答
12

@Mohamad Chami 的例子真的很棒,尝试编写它的 Swift 版本
GitHubLink

class SocketDataManager: NSObject, StreamDelegate {

    var readStream: Unmanaged<CFReadStream>?
    var writeStream: Unmanaged<CFWriteStream>?
    var inputStream: InputStream?
    var outputStream: OutputStream?
    var messages = [AnyHashable]()
    weak var uiPresenter :PresenterProtocol!

    init(with presenter:PresenterProtocol){

        self.uiPresenter = presenter
    }
    func connectWith(socket: DataSocket) {

        CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (socket.ipAddress! as CFString), UInt32(socket.port), &readStream, &writeStream)
        messages = [AnyHashable]()
        open()
    }

    func disconnect(){

        close()
    }

    func open() {
        print("Opening streams.")
        outputStream = writeStream?.takeRetainedValue()
        inputStream = readStream?.takeRetainedValue()
        outputStream?.delegate = self
        inputStream?.delegate = self
        outputStream?.schedule(in: RunLoop.current, forMode: .defaultRunLoopMode)
        inputStream?.schedule(in: RunLoop.current, forMode: .defaultRunLoopMode)
        outputStream?.open()
        inputStream?.open()
    }

    func close() {
        print("Closing streams.")
        uiPresenter?.resetUIWithConnection(status: false)
        inputStream?.close()
        outputStream?.close()
        inputStream?.remove(from: RunLoop.current, forMode: .defaultRunLoopMode)
        outputStream?.remove(from: RunLoop.current, forMode: .defaultRunLoopMode)
        inputStream?.delegate = nil
        outputStream?.delegate = nil
        inputStream = nil
        outputStream = nil
    }

    func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
        print("stream event \(eventCode)")
        switch eventCode {
        case .openCompleted:
            uiPresenter?.resetUIWithConnection(status: true)
            print("Stream opened")
        case .hasBytesAvailable:
            if aStream == inputStream {
                var dataBuffer = Array<UInt8>(repeating: 0, count: 1024)
                var len: Int
                while (inputStream?.hasBytesAvailable)! {
                    len = (inputStream?.read(&dataBuffer, maxLength: 1024))!
                    if len > 0 {
                        let output = String(bytes: dataBuffer, encoding: .ascii)
                        if nil != output {
                            print("server said: \(output ?? "")")
                            messageReceived(message: output!)
                        }
                    }
                }
            }
        case .hasSpaceAvailable:
            print("Stream has space available now")
        case .errorOccurred:
            print("\(aStream.streamError?.localizedDescription ?? "")")
        case .endEncountered:
            aStream.close()
            aStream.remove(from: RunLoop.current, forMode: .defaultRunLoopMode)
            print("close stream")
            uiPresenter?.resetUIWithConnection(status: false)
        default:
            print("Unknown event")
        }
    }

    func messageReceived(message: String){

        uiPresenter?.update(message: "server said: \(message)")
        print(message)
    }

    func send(message: String){

        let response = "msg:\(message)"
        let buff = [UInt8](message.utf8)
        if let _ = response.data(using: .ascii) {
            outputStream?.write(buff, maxLength: buff.count)
        }

    }

}





class ViewController: UIViewController {

    var socketConnector:SocketDataManager!
    @IBOutlet weak var ipAddressField: UITextField!
    @IBOutlet weak var portField: UITextField!
    @IBOutlet weak var messageField: UITextField!
    @IBOutlet weak var messageHistoryView: UITextView!
    @IBOutlet weak var connectBtn: UIButton!
    @IBOutlet weak var sendBtn: UIButton!
    @IBOutlet weak var statusView: UIView!
    @IBOutlet weak var statusLabl: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
        socketConnector = SocketDataManager(with: self)
        resetUIWithConnection(status: false)
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    @IBAction func connect(){
        //http://localhost:50694/
        guard let ipAddr = ipAddressField.text, let portVal = portField.text  else {
            return
        }
        let soc = DataSocket(ip: ipAddr, port: portVal)
        socketConnector.connectWith(socket: soc)

    }
    @IBAction func send(){
        guard let msg = messageField.text else {
            return
        }
        send(message: msg)
        messageField.text = ""
    }
    func send(message: String){

        socketConnector.send(message: message)
        update(message: "me:\(message)")
    }
}

extension ViewController: PresenterProtocol{

    func resetUIWithConnection(status: Bool){

        ipAddressField.isEnabled = !status
        portField.isEnabled = !status
        messageField.isEnabled = status
        connectBtn.isEnabled = !status
        sendBtn.isEnabled = status

        if (status){
            updateStatusViewWith(status: "Connected")
        }else{
            updateStatusViewWith(status: "Disconnected")
        }
    }
    func updateStatusViewWith(status: String){

        statusLabl.text = status
    }

    func update(message: String){

        if let text = messageHistoryView.text{
            let newText = """
            \(text)            
            \(message)
            """
            messageHistoryView.text = newText
        }else{
            let newText = """
            \(message)
            """
            messageHistoryView.text = newText
        }

        let myRange=NSMakeRange(messageHistoryView.text.count-1, 0);
        messageHistoryView.scrollRangeToVisible(myRange)


    }


}


struct DataSocket {

    let ipAddress: String!
    let port: Int!

    init(ip: String, port: String){        
        self.ipAddress = ip
        self.port      = Int(port)
    }
}

样本

于 2018-03-31T16:51:10.407 回答
3

服务器端无法接收数据的:

这可能是由于数据编码机制。@Mohamad Chami 的答案在更改数据编码机制后工作正常,sendMessage方法如下:

在他的示例中,通过以下NSString方式转换为NSData

 NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];

将 更改NSASCIIStringEncodingNSUTF8StringEncoding。这是因为在服务器端(在我的例子中是 Oracle 数据库服务器),数据是以修改后的 UTF-8 编码接收的。

于 2017-06-27T08:45:29.440 回答
3

https://github.com/swiftsocket/SwiftSocket Swift Socket 库为您提供了一个简单的基于套接字的连接接口。请参阅此链接和以下示例。

let client = TCPClient(address: "www.apple.com", port: 80)
switch client.connect(timeout: 1) {
  case .success:
    switch client.send(string: "GET / HTTP/1.0\n\n" ) {
      case .success:
        guard let data = client.read(1024*10) else { return }

        if let response = String(bytes: data, encoding: .utf8) {
          print(response)
        }
      case .failure(let error):
        print(error)
    }
  case .failure(let error):
    print(error)
}

标题

于 2017-03-25T04:47:19.217 回答
2

也许在这里试试:http ://www.raywenderlich.com/3932/how-to-create-a-socket-based-iphone-app-and-server

Ray 给出了使用 Python + iOS 客户端应用程序构建自定义服务器的好例子。他有一套非常好的关于 iOS 主题的教程——值得访问他的网站。

于 2013-09-25T11:19:09.210 回答
0

Apple 的示例展示了如何使用各种 Apple API 来运行 TCP 连接,包括:

  1. 套接字流/流
  2. URLSessionStreamTask
  3. BSD 插座
  4. NWTCP连接
于 2021-05-12T02:03:53.657 回答
0
import Network


@objc protocol TCPConnectionDelegate {
    @objc optional func deviceStatusUpdated(isUpdated:Bool)
    @objc optional func deviceSwitchToNetwork(deviceId:String)
    @objc optional func TcpConnectionState(state:String,ip:String)
}

class TCPConnection:NSObject{

    var delegate:TCPConnectionDelegate?
    var connection: NWConnection?

    final func start(host:NWEndpoint.Host) {
        connection = NWConnection(host: host, port: 1234, using: .tcp)
        connection!.stateUpdateHandler = self.stateDidChange(to:)
        self.setupReceive(on: connection!)
        connection!.start(queue: .main)
        //self.connection = connection
    }
    
    func stateDidChange(to state: NWConnection.State) {
        var ipAddressWithPort = connection!.endpoint.debugDescription
        let ip = ipAddressWithPort.components(separatedBy: ":")
        switch state {
        case .setup:
            break
        case .waiting(let error):
            print("Errrooor",error)
            self.delegate?.TcpConnectionState!(state: error.localizedDescription, ip: ip[0])
        //self.connectionDidFail(error: error)
        case .preparing:
            break
        case .ready:
            print("Readddy",connection?.endpoint.debugDescription)
            
            print("IPAADERESS",ip[0])
            self.delegate?.TcpConnectionState!(state: "Connected",ip: ip[0])
        case .failed(let error):
            print("FAiled",error)
            self.delegate?.TcpConnectionState!(state: error.localizedDescription, ip: ip[0])
        case .cancelled:
            break
        }
      
    }
    
    func setupReceive(on connection: NWConnection) {
        connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { (data, contentContext, isComplete, error) in
            if let data = data, !data.isEmpty {
                
                print("Received:", String(data: data, encoding: .utf8) )
                let stringData = String(data: data, encoding: .utf8)
                let data = stringData!.data(using: .utf8)
                do {
                    let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String:Any]
                    
                   
                    
                    
                    print("REsponseeeeData",json)
                }catch{
                    
                }
                
            }
            if isComplete {
                self.connectionDidEnd()
            } else if let error = error {
                self.connectionDidFail(error: error)
            } else {
                self.setupReceive(on: connection)
            }
        }
    }
    var didStopCallback: ((Error?) -> Void)? = nil
    private func connectionDidFail(error: Error) {
        print("connection did fail, error: \(error)")
        stop(error: error)
    }

    private func connectionDidEnd() {
        print("connection  did end")
        stop(error: nil)
    }
    private func stop(error: Error?) {
        connection!.stateUpdateHandler = nil
        connection!.cancel()
        if let didStopCallback = didStopCallback {
            self.didStopCallback = nil
            didStopCallback(error)
        }
    }
    
    func sendStreamOriented(connection: NWConnection, data: Data) {
        connection.send(content: data, completion: .contentProcessed({ error in
            if let error = error {
                print("Errrorrrr",error)
                //  self.connectionDidFail(error: error)
            }
        }))
    }
    
    func sendEndOfStream(connection: NWConnection) {
        connection.send(content: nil, contentContext: .defaultStream, isComplete: true, completion: .contentProcessed({ error in
            if let error = error {
                print("Errrorrrr11111",error)
                // self.connectionDidFail(error: error)
            }
        }))
    }
    
    func sendMsg(message: [String:Any]) {
        let json = try? JSONSerialization.data(withJSONObject: message, options: .prettyPrinted)
        guard let jsnStr = String(data: json!, encoding: .utf8) else { return }
        print("ekdhkhfkehflhf",jsnStr)
        
        let msg = jsnStr + "\r\n"
        let data: Data? = msg.data(using: .utf8)
        connection!.send(content: data, completion: .contentProcessed { (sendError) in
            if let sendError = sendError {
                print("\(sendError)")
            }
            })
        self.setupReceive(on: connection!)
    }
    
    func cancel() {
        connection!.cancel()
    }
    

}
于 2020-11-23T13:49:29.403 回答