web-dev-qa-db-ja.com

iPhone TCP / IPソケットサーバー/クライアントプログラム

私はこのウェブサイトでこの主題に関する多くの質問を読みましたが、彼らは私の質問に静かに答えませんでした。あなたが私の目標や背景について###になれない場合は、質問にスキップしてください。

私の目標

Mac OS X 10.4以降で実行できるサーバーを構築し、それをWindows XP/Vistaに移植することです(まだその方法はわかりませんが、それは後の問題です)。

次に、iPhoneを、サーバーを実行しているコンピューター名を(WiFiを介して)表示できるクライアントにします。 iPhoneのユーザーは、コンピューター名を選択して、そのコンピューター上のサーバーに接続できます。

その後、簡単なテキストメッセージを互いに送信できます。たとえば、iPhoneは「Knock Knock」を送信し、サーバーは「Who is there?」と応答します。または、単純なクライアント:「Ping」、サーバーは「Pong」と応答しますが、問題ありません。

背景

私は過去にソケットを扱ってきましたが、WINSOCKET.dllを備えたVisual Basic 6でのみ、TCP/IPサーバーを作成するのは非常に簡単でした。

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

クライアントでは、接続するために以下を行うだけで済みました。

client.connect(localhost, 12203);

Connect、close、dataArrivalなど、利用可能なコールバックがいくつかあり、それらを使用して任意の操作を実行できました。

おそらくiPhone用に書かれたライブラリがありますが、この単純なアプリケーションを自分で作成するのは難しいですか?いくつかの調査を行った後、CFNetwork、CFHost、CFSocket、CFStreamの領域を調べる必要があることを理解しています。

質問

IPhoneに2つのボタンがあるチュートリアルに私を案内したり、コードを投稿したりできる人はいますか。 [サーバーの起動]と[サーバーへの接続]では、最初のサーバーが特定のポートでTCP/IPサーバーを起動し、2番目のサーバーがそれに接続します。

接続が確立された後、サーバーがこれを受信した後に単純な「Ping」メッセージをサーバーに送信するコードも、クライアントに「Pong」メッセージで応答します。

それは本当に役立つでしょう。しかし、多分私はここに多くを求めています。

23
Mark

このチュートリアル チャットサンプルアプリを作成することは非常にうまく機能し、非常に簡単です(私のようなiphone noobは、シミュレータモードでも外部ソケットサーバーに接続します)。

ソケットサーバーと通信できるように調整しました。これはテストコードであるため、ルーズエンドに大きな懸念はありません。 1つのメッセージ(ログオンID)を送信し、コンソールに表示される応答を受信します。

//
//  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

あなたのViewController.hファイルには

#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のみ:Ctrlキーを押しながらオブジェクトをコードウィンドウにドラッグして、ボタンとテキストフィールドをリンクする必要があります。これを行うと、上記のプロパティが自動的に作成されます。チェック このビデオチュートリアル 困惑している場合

NOOBSのみ2:このソケットは、XCODEのコンソールペインに出力されます。 Xcodeウィンドウの右上隅で、HIDE OR SHOW THE DEBUG AREA(必要に応じて助けを求める))をクリックします。

snowLeopardにxcode 4.2を使用して、2GBメモリのMacbookで構築およびテスト(シミュレーターおよびデバイス)しました。

18
tony gil

次のことをお勧めします。 Cocoa Async Socket

また、サイトには基本的なサンプルプロジェクトも用意されています。そのフレームワークでの作業は成功しました。

3
Kongress

私はあなたがあなたのサーバーが既に開始されることを望んでいるだろうし、それからあなたは「サーバーに接続する」ボタン、そしてあなたの「Ping」だけを必要とするでしょう。それ以外の場合は、「Start Server」メッセージに応答してサーバーを起動するサーバーボックスに別のプロセスが必要です。

1
Chris Kline