web-dev-qa-db-fra.com

iPhone TCP / IP Socket Server / Client Program

J'ai lu beaucoup de questions sur ce sujet sur ce site Web, mais elles n'ont pas répondu à ma question. Si vous ne pouvez pas être ### sur mon objectif ou mes antécédents, passez à la question.

Mon objectif

Est de construire un serveur qui peut fonctionner sur Mac OS X 10.4+ et versions ultérieures, le porter sur Windows XP/Vista (je ne sais pas encore comment le faire, mais c'est un problème pour plus tard).

Ensuite, laissez l'iPhone être le client qui peut voir les noms des ordinateurs qui exécutent le serveur (via WiFi). L'utilisateur de l'iPhone peut alors sélectionner le nom de l'ordinateur pour se connecter au serveur sur cet ordinateur.

Après cela, ils peuvent s’envoyer de simples messages texte. Par exemple, l'iPhone envoie "Knock Knock" et le serveur répond "Qui est là?". Ou un simple client: "Ping", le serveur répond "Pong" fera très bien l'affaire.

Contexte

J'ai travaillé avec des sockets dans le passé, mais uniquement dans Visual Basic 6 avec WINSOCKET.dll, il était très facile de créer un serveur TCP/IP.

server.Host = localhost;
server.port = 12203;
server.listen(); 

Avec le client, je n'avais qu'à faire ce qui suit pour me connecter.

client.connect(localhost, 12203);

Il y avait des rappels disponibles comme connect, close, dataArrival, etc. que je pouvais utiliser pour faire tout ce que je voulais.

Peut-être que pour l'iPhone, il existe des bibliothèques écrites pour cela, mais est-ce si difficile de créer vous-même cette application simple? Après avoir fait quelques recherches, je comprends que je dois regarder dans le domaine de CFNetwork, CFHost, CFSocket, CFStream.

Question

Y a-t-il quelqu'un qui pourrait me guider vers un tutoriel ou poster le code où vous avez deux boutons sur l'iPhone. [Démarrer le serveur] et [Se connecter au serveur] où le premier démarre un serveur TCP/IP sur un certain port et le second s'y connecte.

Une fois la connexion établie, peut-être aussi le code pour envoyer un simple message "Ping" au serveur après réception par le serveur, il répond avec un message "Pong" au client.

Ce serait vraiment utile. Mais peut-être que je demande trop ici.

23
Mark

ce tutoriel pour créer un exemple d'application de chat fonctionne très bien et est assez simple (tout noob iphone, comme moi, peut le faire fonctionner, MÊME EN MODE SIMULATEUR, il se connecte à un serveur de socket externe).

je l'ai adapté pour parler mon serveur de socket et cela fonctionne comme un charme. c'est du code de test, donc il n'y a pas vraiment de problème avec les extrémités lâches. il n'envoie qu'un seul message (votre identifiant de connexion) et reçoit une réponse, qu'il affiche dans la console.

//
//  ViewController.m
//  zdelSocketTest01a
//
//

#import "ViewController.h"



@implementation ViewController
@synthesize inputNameField;
@synthesize joinView;

- (void)initNetworkCommunication {

    uint portNo = 5555;
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;
    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"227.3.4.56", portNo, &readStream, &writeStream);
    inputStream = (__bridge NSInputStream *)readStream;
    outputStream = (__bridge NSOutputStream *)writeStream;

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

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

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self initNetworkCommunication];
    messages = [[NSMutableArray alloc] init];
}

- (void)viewDidUnload
{
    [self setInputNameField:nil];
    [self setJoinView:nil];
    [self setJoinView:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

- (IBAction)joinChat:(id)sender {

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

}
/*
 - (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
 NSLog(@"stream event %i", streamEvent);
 }
 */

- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
    typedef enum {
        NSStreamEventNone = 0,
        NSStreamEventOpenCompleted = 1 << 0,
        NSStreamEventHasBytesAvailable = 1 << 1,
        NSStreamEventHasSpaceAvailable = 1 << 2,
        NSStreamEventErrorOccurred = 1 << 3,
        NSStreamEventEndEncountered = 1 << 4
    };
    uint8_t buffer[1024];
    int len;

    switch (streamEvent) {

        case NSStreamEventOpenCompleted:
            NSLog(@"Stream opened now");
            break;
        case NSStreamEventHasBytesAvailable:
            NSLog(@"has bytes");
            if (theStream == inputStream) {
                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);
                        }
                    }
                }
            } else {
                NSLog(@"it is NOT theStream == inputStream");
            }
            break;
        case NSStreamEventHasSpaceAvailable:
            NSLog(@"Stream has space available now");
            break;


        case NSStreamEventErrorOccurred:
            NSLog(@"Can not connect to the Host!");
            break;


        case NSStreamEventEndEncountered:

            [theStream close];
            [theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

            break;

        default:
            NSLog(@"Unknown event %i", streamEvent);
    }

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

 [messages addObject:message];
 [self.tView reloadData];

 }
 */

@end

votre fichier ViewController.h contiendrait

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <NSStreamDelegate>
@property (weak, nonatomic) IBOutlet UITextField *inputNameField;
@property (weak, nonatomic) IBOutlet UIView *joinView;
- (IBAction)joinChat:(id)sender;


@end
NSInputStream *inputStream;
NSOutputStream *outputStream;
NSMutableArray * messages;

NOOBS UNIQUEMENT: vous devez lier votre bouton et votre champ de texte en appuyant sur CONTROL et en faisant glisser l'objet dans la fenêtre de code. lorsque vous faites cela, les propriétés ci-dessus seront automatiquement créées. vérifier ce tutoriel vidéo si vous êtes perplexe

NOOBS ONLY 2: cette prise sortira dans le CONSOLE PANE de XCODE. dans le coin supérieur droit de votre fenêtre xcode, cliquez sur MASQUER OR AFFICHER LA ZONE DE DÉBOGAGE (demandez de l'aide si nécessaire).

construit et testé (simulateur et appareil) sur un macbook avec 2 Go de mémoire, en utilisant xcode 4.2 pour snow leopard.

18
tony gil

Je recommande ce qui suit: Cocoa Async Socket

Il existe également un exemple de projet de base sur le site pour vous aider à démarrer. J'ai eu beaucoup de succès à travailler avec ce cadre.

3
Kongress

Je m'attendrais à ce que vous souhaitiez que votre serveur soit déjà démarré, et alors vous n'auriez besoin que d'un bouton "Se connecter au serveur", puis de votre "Ping". Sinon, vous avez besoin d'un processus distinct sur votre boîtier de serveur qui répond au message "Démarrer le serveur" et démarre le serveur.

1
Chris Kline