Ok, j'ai un problème avec la construction d'une socket avec Objective-C. Si vous jetez un oeil à mon code ci-dessous, grâce à l'aide de l'exemple de code et d'autres sources, j'ai été en mesure de construire un socket complet, je crois. Le problème est que lorsque je le compile, il se construit très bien (pas de problèmes de syntaxe), mais il n'y a pas de socket créé. Comme vous remarquerez que j'ai commenté beaucoup de choses dans Server2.m et ai isolé le problème au tout début quand je crée la structure pour le listeningSocket. En passant, si cela aide, il fait partie du côté serveur de l'application client-serveur. Est-ce que quelqu'un sait pourquoi je vais avoir ce problème? Tout semblait fonctionner correctement hier, et ce matin, j'ai pensé que j'allais adopter une approche différente pour construire les prises, alors j'ai essayé cela. Merci pour toute aide!Problème lors de la création de sockets à l'aide de CFSocket dans Objective-C (application iPhone)
Server_TrialViewController.m
#include <CFNetwork/CFSocketStream.h>
#import <UIKit/UIKit.h>
#import "Server2.h"
#import "Client_Test.h"
@interface Server_TrialViewController : UIViewController {
IBOutlet UIButton *ServerButton;
IBOutlet UIButton *ClientButton;
IBOutlet UILabel *statusLabel;
Server2 *server;
Client_Test *client;
}
@property(nonatomic, retain) UILabel *statusLabel;
@property(nonatomic, retain) Server2 *server;
@property(nonatomic, retain) Client_Test *client;
-(IBAction)serverButtonPressed;
-(IBAction)clientButtonPressed;
//-(void)sendMessageWithServer:(Server_Test *)SERVER AndClient:(Client_Test *)CLIENT;
@end
Server_TrialViewController.h
#import "Server_TrialViewController.h"
@implementation Server_TrialViewController
@synthesize statusLabel;
@synthesize server;
@synthesize client;
-(IBAction)serverButtonPressed {
if ([server start]) {
[statusLabel setText:@"Success"];
}
else {
if (server.status == NULL) {
[statusLabel setText: @"No Server: No statUpdate"];
}
else {
[statusLabel setText: @"No Server: Found statUpdate"];
}
}
}
-(IBAction)clientButtonPressed {
if ([client start]) {
[statusLabel setText:@"Client Started"];
}
else {
[statusLabel setText:@"Client Not Started"];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
[super dealloc];
}
@end
Server2.h
#import <Foundation/Foundation.h>
#import "Server2Delegate.h"
@interface Server2 : NSObject
{
uint16_t port;
CFSocketRef listeningSocket;
id<Server2Delegate> delegate;
NSNetService* netService;
NSString *status;
}
// Initialize connection
- (BOOL)start;
- (void)stop;
// Delegate receives various notifications about the state of our server
@property(nonatomic,retain) id<Server2Delegate> delegate;
@property(nonatomic, retain) NSString *status;
@end
Server2.m
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <CFNetwork/CFSocketStream.h>
#import "Server2.h"
#import "Connection2.h"
#import "AppConfig2.h"
// Declare some private properties and methods
@interface Server2()
@property(nonatomic,assign) uint16_t port;
@property(nonatomic,retain) NSNetService* netService;
-(BOOL)createServer;
-(void)terminateServer;
@end
// Implementation of the Server interface
@implementation Server2
@synthesize delegate;
@synthesize port, netService;
@synthesize status;
// Cleanup
- (void)dealloc
{
self.netService = nil;
self.delegate = nil;
[super dealloc];
}
// Create server and announce it
- (BOOL)start
{
// Start the socket server
if (! [self createServer])
{
status = @"Server Not Created";
return FALSE;
}
status = @"Server Created";
return TRUE;
}
// Close everything
- (void)stop {
[self terminateServer];
}
#pragma mark Callbacks
// Handle new connections
- (void)handleNewNativeSocket:(CFSocketNativeHandle)nativeSocketHandle {
Connection2* connection = [[[Connection2 alloc] initWithNativeSocketHandle:nativeSocketHandle] autorelease];
// In case of errors, close native socket handle
if (connection == nil) {
close(nativeSocketHandle);
return;
}
// finish connecting
if (! [connection connect]) {
//status = @"Connection Not Made";
[connection close];
return;
}
//status = @"Connection Made";
// Pass this on to our delegate
[delegate handleNewConnection:connection];
}
// This function will be used as a callback while creating our listening socket via 'CFSocketCreate'
static void serverAcceptCallback(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
Server2 *server = (Server2*)info;
// We can only process "connection accepted" calls here
if (type != kCFSocketAcceptCallBack) {
return;
}
// for an AcceptCallBack, the data parameter is a pointer to a CFSocketNativeHandle
CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle*)data;
[server handleNewNativeSocket:nativeSocketHandle];
}
#pragma mark Sockets and streams
- (BOOL)createServer
{
//// PART 1: Create a socket that can accept connections
// Socket context
// struct CFSocketContext {
// CFIndex version;
// void *info;
// CFAllocatorRetainCallBack retain;
// CFAllocatorReleaseCallBack release;
// CFAllocatorCopyDescriptionCallBack copyDescription;
// };
CFSocketContext socketContext = {0, self, NULL, NULL, NULL};
listeningSocket = CFSocketCreate(
kCFAllocatorDefault,
PF_INET, // The protocol family for the socket
SOCK_DGRAM, // The socket type to create
IPPROTO_UDP, // The protocol for the socket. TCP vs UDP.
0, //kCFSocketAcceptCallBack, // New connections will be automatically accepted and the callback is called with the data argument being a pointer to a CFSocketNativeHandle of the child socket.
NULL, //(CFSocketCallBack)&serverAcceptCallback,
&socketContext);
// Previous call might have failed
if (listeningSocket == NULL) {
status = @"listeningSocket Not Created";
return FALSE;
}
else {
status = @"listeningSocket Created";
return TRUE;
}
}
/*
// getsockopt will return existing socket option value via this variable
int existingValue = 1;
// Make sure that same listening socket address gets reused after every connection
setsockopt(CFSocketGetNative(listeningSocket),
SOL_SOCKET, SO_REUSEADDR, (void *)&existingValue,
sizeof(existingValue));
//// PART 2: Bind our socket to an endpoint.
// We will be listening on all available interfaces/addresses.
// Port will be assigned automatically by kernel.
struct sockaddr_in socketAddress;
memset(&socketAddress, 0, sizeof(socketAddress));
socketAddress.sin_len = sizeof(socketAddress);
socketAddress.sin_family = AF_INET; // Address family (IPv4 vs IPv6)
socketAddress.sin_port = 0; // Actual port will get assigned automatically by kernel
socketAddress.sin_addr.s_addr = htonl(INADDR_ANY); // We must use "network byte order" format (big-endian) for the value here
// Convert the endpoint data structure into something that CFSocket can use
NSData *socketAddressData =
[NSData dataWithBytes:&socketAddress length:sizeof(socketAddress)];
// Bind our socket to the endpoint. Check if successful.
if (CFSocketSetAddress(listeningSocket, (CFDataRef)socketAddressData) != kCFSocketSuccess) {
// Cleanup
if (listeningSocket != NULL) {
status = @"Socket Not Binded";
CFRelease(listeningSocket);
listeningSocket = NULL;
}
return FALSE;
}
status = @"Socket Binded";
//// PART 3: Find out what port kernel assigned to our socket
// We need it to advertise our service via Bonjour
NSData *socketAddressActualData = [(NSData *)CFSocketCopyAddress(listeningSocket) autorelease];
// Convert socket data into a usable structure
struct sockaddr_in socketAddressActual;
memcpy(&socketAddressActual, [socketAddressActualData bytes],
[socketAddressActualData length]);
self.port = ntohs(socketAddressActual.sin_port);
//// PART 4: Hook up our socket to the current run loop
CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent();
CFRunLoopSourceRef runLoopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, listeningSocket, 0);
CFRunLoopAddSource(currentRunLoop, runLoopSource, kCFRunLoopCommonModes);
CFRelease(runLoopSource);
return TRUE;
}
*/
- (void) terminateServer {
if (listeningSocket != nil) {
CFSocketInvalidate(listeningSocket);
CFRelease(listeningSocket);
listeningSocket = nil;
}
}
#pragma mark -
#pragma mark NSNetService Delegate Method Implementations
// Delegate method, called by NSNetService in case service publishing fails for whatever reason
- (void)netService:(NSNetService*)sender didNotPublish:(NSDictionary*)errorDict {
if (sender != self.netService) {
return;
}
// Stop socket server
[self terminateServer];
}
@end
CFSocketStream inclut le mot "flux" pour indiquer qu'il s'agit de connexions orientées flux. Dans Apple, ils pensent que c'est tout aussi évident que possible, mais ce n'est clairement pas le cas. – uchuugaka