Ok, tôi gặp sự cố khi tạo ổ cắm bằng Objective-C. Nếu bạn sẽ xem xét mã của tôi dưới đây, thông qua trợ giúp với mã ví dụ và các nguồn khác, tôi đã có thể xây dựng một ổ cắm hoàn chỉnh mà tôi tin. Vấn đề là khi tôi biên dịch nó, nó xây dựng tốt (không có vấn đề cú pháp), nhưng không có ổ cắm được tạo ra. Như bạn sẽ nhận thấy tôi đã nhận xét ra rất nhiều thứ trong Server2.m và đã phân lập vấn đề ngay từ đầu khi tôi tạo cấu trúc cho listenSocket. Bằng cách này, nếu điều này giúp, nó là một phần của phía máy chủ của ứng dụng máy khách-khách hàng. Có ai biết tại sao tôi sẽ nhận được vấn đề này? Tất cả mọi thứ dường như làm việc tốt đẹp ngày hôm qua, và sáng nay tôi nghĩ rằng tôi sẽ có một cách tiếp cận khác nhau để xây dựng các ổ cắm, vì vậy tôi đã cố gắng này. Cảm ơn vì bất kì sự giúp đỡ!Sự cố khi tạo ổ cắm bằng CFSocket trong Objective-C (ứng dụng 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 bao gồm từ "luồng" để cho biết đó là các kết nối được định hướng luồng. Trong Apple, họ nghĩ điều này rõ ràng là có thể, nhưng rõ ràng là không. – uchuugaka