iPhone TCP/IP Socket 服务器/客户端程序
-
08-07-2019 - |
题
我在这个网站上读到了很多关于这个主题的问题,但是他们没有安静地回答我的问题。如果您无法了解我的目标或背景,请跳至该问题。
我的目标
就是构建一个可以在 Mac OS X 10.4+ 及更高版本上运行的服务器,将其移植到 Windows XP/Vista(还不知道如何做到这一点,但这是以后的问题)。
然后让 iPhone 成为客户端,能够看到正在运行服务器的计算机名称(通过 WiFi)。然后,iPhone 用户可以选择计算机名称以连接到该计算机上的服务器。
之后他们可以互相发送简单的短信。例如,iPhone 发送“敲门”,服务器响应“谁在那儿?”。或者一个简单的客户端:“Ping”,服务器响应“Pong”就可以了。
背景
我过去曾使用过套接字,但只有在 Visual Basic 6 中使用 WINSOCKET.dll 才能非常轻松地创建 TCP/IP 服务器。
server.host = localhost;
server.port = 12203;
server.listen();
对于客户端,我只需要执行以下操作即可连接。
client.connect(localhost, 12203);
有一些可用的回调,例如 connect、close、dataArrival 等。我可以用它来做任何我想做的事情。
也许有专门为 iPhone 编写的库,但是自己创建这个简单的应用程序有那么难吗?经过一些研究后,我明白我必须关注 CFNetwork、CFHost、CFSocket、CFStream 领域。
问题
有没有人可以指导我教程或发布 iPhone 上有两个按钮的代码。[ 启动服务器 ] 和 [ 连接到服务器 ],第一个将在某个端口上启动 TCP/IP 服务器,第二个将连接到该服务器。
建立连接后,服务器收到此消息后,可能还会向服务器发送简单的“Ping”消息,并向客户端发送“Pong”消息。
这真的很有帮助。但也许我在这里要求太多了。
解决方案
本教程 创建一个聊天示例应用程序效果很好,而且非常简单(任何像我这样的 iPhone 菜鸟都可以使其工作,即使在模拟器模式下,它也连接到外部套接字服务器)。
我改编它来与我的套接字服务器对话,它的工作方式就像一个魅力。这是测试代码,因此不必真正担心未解决的问题。它只发送一条消息(您的登录 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;
仅限菜鸟:您必须通过按 CONTROL 并将对象拖到代码窗口中来链接按钮和文本字段。当您这样做时,将自动创建上述属性。查看 这个视频教程 如果你被难住了
仅限菜鸟 2:该套接字将在 XCODE 的 CONSOLE PANE 中输出。在 xcode 窗口的右上角,单击“隐藏或显示调试区域”(如有必要,请寻求帮助)。
使用适用于雪豹的 xcode 4.2 在具有 2GB 内存的 MacBook 上构建并测试(模拟器和设备)。
其他提示
我推荐以下内容: Cocoa Async Socket
网站上还有一个基本的示例项目可以帮助您入门。我在使用该框架方面取得了很大的成功。
我希望您希望自己的服务器已经启动,然后您只需要“连接到服务器”即可。按钮,然后你的“Ping”。否则,您需要在服务器上使用单独的进程来响应“启动服务器”。消息并启动服务器。