ios iOS简单TCP连接示例

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19003063/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:40:52  来源:igfitidea点击:

iOS simple TCP connection example

iostcp

提问by Sean

Does anyone know of a simple TCP example for iOS devices so I can send a string to a server. I've had a look at the following library https://github.com/robbiehanson/CocoaAsyncSocketbut it seems very verbose.

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

All I really want is to have a simple way of connecting to an IP address & port number and sending a string of data to this address. Does anyone know of a simple way to do this?

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

回答by Mohamad Chami

SocketConnectionVC.h

套接字连接VC.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

SocketConnectionVC.m

SocketConnectionVC.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

snapshot for ui of this SocketConnectionVCenter image description here

此 SocketConnectionVC 的 ui 快照在此处输入图片说明

and Follow these steps

并按照以下步骤操作

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

回答by anoop4real

@Mohamad Chami's example was really great, tried to write a Swift version of it
GitHubLink

@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)
    }
}

Sample

样本

回答by HamasN

https://github.com/swiftsocket/SwiftSocketSwift Socket library provide you a simple interface for socket based connection. Refer to this link and below sample.

https://github.com/swiftsocket/SwiftSocketSwift 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)
}

Heading

标题

回答by santobedi

Those who are unable to receive data at the server side:

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

It is perhaps due to data encoding mechanism. @Mohamad Chami's answer works fine after changing the data encoding mechanism at the sendMessagemethod as follows:

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

In his example, NSStringis converted to NSDataby:

在他的例子中,NSString被转换为NSData

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

Change the NSASCIIStringEncodingto NSUTF8StringEncoding. It is because at server's side (Oracle database server in my case), the data is received in modified UTF-8 encoding.

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

回答by TheRook

Maybe try here: http://www.raywenderlich.com/3932/how-to-create-a-socket-based-iphone-app-and-server

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

Ray gives nice example of building custom server using Python + iOS client application. He has very nice set of tutorials on iOS topics - it is worth to visit his site.

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