有没有人知道iOS设备的简单TCP示例,因此我可以将字符串发送到服务器。我已经看过下面的库https://github.com/robbiehanson/CocoaAsyncSocket,但它看起来非常冗长。
我真正想要的只是一种简单的方法来连接到IP地址&端口号并将一串数据发送到此地址。有谁知道这样做的简单方法?
答案 0 :(得分:21)
<强> 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
答案 1 :(得分:4)
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)
}
}
答案 2 :(得分: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)
}
答案 3 :(得分:3)
无法在服务器端接收数据的人:
这可能是由于数据编码机制造成的。 @Mohamad Chami的答案在itertools.islice
方法更改数据编码机制后工作正常,如下所示:
在他的示例中,sendMessage
被转换为NSString
:
NSData
将 NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
更改为NSASCIIStringEncoding
。这是因为在服务器端(在我的情况下是Oracle数据库服务器),数据是以修改的UTF-8编码接收的。
答案 4 :(得分:2)
也许可以在这里试试:http://www.raywenderlich.com/3932/how-to-create-a-socket-based-iphone-app-and-server
Ray提供了使用Python + iOS客户端应用程序构建自定义服务器的好例子。他有关于iOS主题的非常好的教程 - 值得访问他的网站。
答案 5 :(得分: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()
}
}
答案 6 :(得分:0)
Sample from Apple 展示了如何使用各种 Apple API 来运行 TCP 连接,包括: