有没有人知道iOS设备的简单TCP示例,所以我可以将字符串发送到服务器。我看过下面的库https://github.com/robbiehanson/CocoaAsyncSocket,但它看起来非常冗长。
我真正想要的是有一种简单的方法来连接到IP地址和端口号,并将一串数据发送到该地址。有谁知道这样做的简单方法?
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
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
并按照这些步骤
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
@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)
}
}
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)
}
那些无法在服务器端接收数据的人:
这或许是由于数据编码机制。 @Mohamad Chami的答案在sendMessage
方法中更改数据编码机制后工作正常,如下所示:
在他的例子中,NSString
被转换为NSData
:
NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
将qazxsw poi改为qazxsw poi。这是因为在服务器端(在我的情况下是Oracle数据库服务器),数据是以修改的UTF-8编码接收的。
也许试试这里:NSASCIIStringEncoding
Ray提供了使用Python + iOS客户端应用程序构建自定义服务器的好例子。他有关于iOS主题的非常好的教程 - 值得访问他的网站。