2009-09-17 107 views
20

我已經閱讀了很多關於這個主題在這個網站上的問題,但他們並沒有安靜回答我的問題。如果你不能成爲###關於我的目標或背景跳到問題。iPhone TCP/IP套接字服務器/客戶端程序

我的目標

是將它構建可以在Mac OS X 10.4以上運行,後來的服務器,端口到Windows XP/Vista的(不知道如何做到這一點呢,但是這是一個問題爲以後)。

然後讓iPhone成爲能夠看到運行服務器的計算機名稱(通過WiFi)的客戶端。 iPhone的用戶然後可以選擇計算機名稱以連接到該計算機上的服務器。

之後,他們可以發送簡單的文字信息給對方。例如,iPhone發送「Knock Knock」,服務器響應「誰在那裏?」。或者是一個簡單的客戶端:'Ping',服務器響應'Pong'會做得很好。

背景

我在過去與插座的工作,但只有在Visual Basic 6與WINSOCKET.dll這是非常容易地創建一個TCP/IP服務器。

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

與客戶端我只需要做以下連接。

client.connect(localhost, 12203); 

有一些回調可用,如連接,關閉,dataArrival等,我可以用它來做我想做的任何事情。

也許iPhone有爲它編寫的庫,但難以自己創建這個簡單的應用程序嗎?在做了一些研究後,我明白我必須查看CFNetwork,CFHost,CFSocket,CFStream等領域。

問題

是否有任何人能指導我的教程或張貼,你必須在iPhone上的兩個按鈕的代碼。 [啓動服務器]和[連接到服務器],第一個將在某個端口上啓動TCP/IP服務器,第二個連接到該服務器。

建立連接後,也可能在服務器收到此消息後向服務器發送簡單'Ping'消息的代碼以'Pong'消息向客戶端迴應。

這真的會有所幫助。但也許我在這裏要求很多。

+0

如果你至少評論每個答案,你不會問太多。爲解決方案投票也會非常好。 ;) – 2013-09-04 17:48:58

回答

17

this tutorialthis tutorial創建一個聊天示例應用程序工作得很好,而且非常簡單(任何iphone noob,像我一樣,都可以使其工作,即使在SIMULATOR MODE中它也可以連接到外部套接字服務器)。

我調整它來談我的套接字服務器,它的作用就像一個魅力。這是測試代碼,所以沒有真正關心的鬆散結局。它只會發送一條消息(您的登錄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; 

菜鳥ONLY:你必須通過按Ctrl並拖動對象到代碼窗口中的鏈接按鈕和文本字段。當你這樣做時,上面的屬性會自動創建。檢查this video tutorial如果你難倒

NOOBS ONLY 2:此套接字將輸出在XCODE的CONSOLE PANE中。在xcode窗口的右上角單擊隱藏或顯示調試區域(如果需要,請尋求幫助)。

在2GB內存的macbook上構建和測試(模擬器和設備),使用xcode 4.2進行雪豹。

+2

非常感謝。對我有幫助。 – piggy 2013-09-02 14:07:03

+1

我們可以有工作副本的源代碼嗎? – 2014-02-09 13:34:06

+0

@FahimParkar這是工作版本的源代碼。如果你覺得這很有用,我希望你記得如果可能的話投票。韓國社交協會。 ;) – 2014-02-09 14:37:50

1

我希望你會希望你的服務器已經啓動,然後你只需要一個「連接到服務器」按鈕,然後你的「平」。否則,您的服務器盒上需要一個單獨的進程來響應「啓動服務器」消息並啓動服務器。

+0

哦,這就是它的工作原理?爲了能夠將服務器檢測爲客戶端,可以將消息發送到某個本地IP範圍(例如,192.168.1.1 - > 255),並且每個服務器都回復該消息並放入您的TableView中。好吧,我會得到的。 – Mark 2009-09-28 10:35:37

+0

有沒有辦法幫助我解決問題的第二部分?如何獲得兩者之間的ping? – Mark 2009-09-28 10:36:30

+2

谷歌廣播端口。 – 2009-10-30 22:43:55

3

我建議如下: Cocoa Async Socket

還有現場讓你開始一個基本的例子項目。我在這個框架上取得了很好的成功。