HTTPServer.m
上传用户:kc0325
上传日期:2020-06-20
资源大小:204k
文件大小:9k
源码类别:

iPhone

开发平台:

Objective-C

  1. #import "AsyncSocket.h"
  2. #import "HTTPServer.h"
  3. #import "HTTPConnection.h"
  4. @implementation HTTPServer
  5. /**
  6.  * Standard Constructor.
  7.  * Instantiates an HTTP server, but does not start it.
  8. **/
  9. - (id)init
  10. {
  11. if(self = [super init])
  12. {
  13. // Initialize underlying asynchronous tcp/ip socket
  14. asyncSocket = [[AsyncSocket alloc] initWithDelegate:self];
  15. // Use default connection class of HTTPConnection
  16. connectionClass = [HTTPConnection self];
  17. // Configure default values for bonjour service
  18. // Use a default port of 0
  19. // This will allow the kernel to automatically pick an open port for us
  20. port = 0;
  21. // Bonjour domain. Use the local domain by default
  22. domain = @"local.";
  23. // If using an empty string ("") for the service name when registering,
  24. // the system will automatically use the "Computer Name".
  25. // Passing in an empty string will also handle name conflicts
  26. // by automatically appending a digit to the end of the name.
  27. name = @"";
  28. // Initialize an array to hold all the HTTP connections
  29. connections = [[NSMutableArray alloc] init];
  30. // And register for notifications of closed connections
  31. [[NSNotificationCenter defaultCenter] addObserver:self
  32.  selector:@selector(connectionDidDie:)
  33.  name:HTTPConnectionDidDieNotification
  34.    object:nil];
  35. }
  36. return self;
  37. }
  38. /**
  39.  * Standard Deconstructor.
  40.  * Stops the server, and clients, and releases any resources connected with this instance.
  41. **/
  42. - (void)dealloc
  43. {
  44. // Remove notification observer
  45. [[NSNotificationCenter defaultCenter] removeObserver:self];
  46. // Stop the server if it's running
  47. [self stop];
  48. // Release all instance variables
  49. [documentRoot release];
  50. [netService release];
  51.     [domain release];
  52.     [name release];
  53.     [type release];
  54. [txtRecordDictionary release];
  55. [asyncSocket release];
  56. [connections release];
  57. [super dealloc];
  58. }
  59. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  60. #pragma mark Server Configuration:
  61. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  62. /**
  63.  * Returns the delegate connected with this instance.
  64. **/
  65. - (id)delegate
  66. {
  67. return delegate;
  68. }
  69. /**
  70.  * Sets the delegate connected with this instance.
  71. **/
  72. - (void)setDelegate:(id)newDelegate
  73. {
  74. delegate = newDelegate;
  75. }
  76. /**
  77.  * The document root is filesystem root for the webserver.
  78.  * Thus requests for /index.html will be referencing the index.html file within the document root directory.
  79.  * All file requests are relative to this document root.
  80. **/
  81. - (NSURL *)documentRoot {
  82.     return documentRoot;
  83. }
  84. - (void)setDocumentRoot:(NSURL *)value
  85. {
  86.     if(![documentRoot isEqual:value])
  87. {
  88.         [documentRoot release];
  89.         documentRoot = [value copy];
  90.     }
  91. }
  92. /**
  93.  * The connection class is the class that will be used to handle connections.
  94.  * That is, when a new connection is created, an instance of this class will be intialized.
  95.  * The default connection class is HTTPConnection.
  96.  * If you use a different connection class, it is assumed that the class extends HTTPConnection
  97. **/
  98. - (Class)connectionClass {
  99.     return connectionClass;
  100. }
  101. - (void)setConnectionClass:(Class)value
  102. {
  103.     connectionClass = value;
  104. }
  105. /**
  106.  * Domain on which to broadcast this service via Bonjour.
  107.  * The default domain is @"local".
  108. **/
  109. - (NSString *)domain {
  110.     return domain;
  111. }
  112. - (void)setDomain:(NSString *)value
  113. {
  114. if(![domain isEqualToString:value])
  115. {
  116. [domain release];
  117.         domain = [value copy];
  118.     }
  119. }
  120. /**
  121.  * The type of service to publish via Bonjour.
  122.  * No type is set by default, and one must be set in order for the service to be published.
  123. **/
  124. - (NSString *)type {
  125.     return type;
  126. }
  127. - (void)setType:(NSString *)value
  128. {
  129. if(![type isEqualToString:value])
  130. {
  131. [type release];
  132. type = [value copy];
  133.     }
  134. }
  135. /**
  136.  * The name to use for this service via Bonjour.
  137.  * The default name is an empty string,
  138.  * which should result in the published name being the host name of the computer.
  139. **/
  140. - (NSString *)name {
  141.     return name;
  142. }
  143. - (NSString *)publishedName {
  144. return [netService name];
  145. }
  146. - (void)setName:(NSString *)value
  147. {
  148. if(![name isEqualToString:value])
  149. {
  150.         [name release];
  151.         name = [value copy];
  152.     }
  153. }
  154. /**
  155.  * The port to listen for connections on.
  156.  * By default this port is initially set to zero, which allows the kernel to pick an available port for us.
  157.  * After the HTTP server has started, the port being used may be obtained by this method.
  158. **/
  159. - (UInt16)port {
  160.     return port;
  161. }
  162. - (void)setPort:(UInt16)value {
  163.     port = value;
  164. }
  165. /**
  166.  * The extra data to use for this service via Bonjour.
  167. **/
  168. - (NSDictionary *)TXTRecordDictionary {
  169. return txtRecordDictionary;
  170. }
  171. - (void)setTXTRecordDictionary:(NSDictionary *)value
  172. {
  173. if(![txtRecordDictionary isEqualToDictionary:value])
  174. {
  175. [txtRecordDictionary release];
  176. txtRecordDictionary = [value copy];
  177. // And update the txtRecord of the netService if it has already been published
  178. if(netService)
  179. {
  180. [netService setTXTRecordData:[NSNetService dataFromTXTRecordDictionary:txtRecordDictionary]];
  181. }
  182. }
  183. }
  184. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  185. #pragma mark Server Control:
  186. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  187. - (BOOL)start:(NSError **)error
  188. {
  189. BOOL success = [asyncSocket acceptOnPort:port error:error];
  190. if(success)
  191. {
  192. // Update our port number
  193. [self setPort:[asyncSocket localPort]];
  194. // Output console message for debugging purposes
  195. NSLog(@"Started HTTP server on port %hu", port);
  196. // We can only publish our bonjour service if a type has been set
  197. if(type != nil)
  198. {
  199. // Create the NSNetService with our basic parameters
  200. netService = [[NSNetService alloc] initWithDomain:domain type:type name:name port:port];
  201. [netService setDelegate:self];
  202. [netService publish];
  203. // Do not set the txtRecordDictionary prior to publishing!!!
  204. // This will cause the OS to crash!!!
  205. // Set the txtRecordDictionary if we have one
  206. if(txtRecordDictionary != nil)
  207. {
  208. [netService setTXTRecordData:[NSNetService dataFromTXTRecordDictionary:txtRecordDictionary]];
  209. }
  210. }
  211. }
  212. else
  213. {
  214. NSLog(@"Failed to start HTTP Server: %@", *error);
  215. }
  216. return success;
  217. }
  218. - (BOOL)stop
  219. {
  220. // First stop publishing the service via bonjour
  221. if(netService)
  222. {
  223. [netService stop];
  224. [netService release];
  225. netService = nil;
  226. }
  227. // Now stop the asynchronouse tcp server
  228. // This will prevent it from accepting any more connections
  229. [asyncSocket disconnect];
  230. // Now stop all HTTP connections the server owns
  231. @synchronized(connections)
  232. {
  233. [connections removeAllObjects];
  234. }
  235. return YES;
  236. }
  237. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  238. #pragma mark Server Status:
  239. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  240. /**
  241.  * Returns the number of clients that are currently connected to the server.
  242. **/
  243. - (uint)numberOfHTTPConnections
  244. {
  245. uint result = 0;
  246. @synchronized(connections)
  247. {
  248. result = [connections count];
  249. }
  250. return result;
  251. }
  252. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  253. #pragma mark AsyncSocket Delegate Methods:
  254. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  255. -(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
  256. {
  257. id newConnection = [[connectionClass alloc] initWithAsyncSocket:newSocket forServer:self];
  258. @synchronized(connections)
  259. {
  260. [connections addObject:newConnection];
  261. }
  262. [newConnection release];
  263. }
  264. /**
  265.  * This method is automatically called when a notification of type HTTPConnectionDidDieNotification is posted.
  266.  * It allows us to remove the connection from our array.
  267. **/
  268. - (void)connectionDidDie:(NSNotification *)notification
  269. {
  270. // Note: This method is called on the thread/runloop that posted the notification
  271. @synchronized(connections)
  272. {
  273. [connections removeObject:[notification object]];
  274. }
  275. }
  276. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  277. #pragma mark Bonjour Delegate Methods:
  278. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  279. /**
  280.  * Called when our bonjour service has been successfully published.
  281.  * This method does nothing but output a log message telling us about the published service.
  282. **/
  283. - (void)netServiceDidPublish:(NSNetService *)ns
  284. {
  285. // Override me to do something here...
  286. NSLog(@"Bonjour Service Published: domain(%@) type(%@) name(%@)", [ns domain], [ns type], [ns name]);
  287. }
  288. /**
  289.  * Called if our bonjour service failed to publish itself.
  290.  * This method does nothing but output a log message telling us about the published service.
  291. **/
  292. - (void)netService:(NSNetService *)ns didNotPublish:(NSDictionary *)errorDict
  293. {
  294. // Override me to do something here...
  295. NSLog(@"Failed to Publish Service: domain(%@) type(%@) name(%@)", [ns domain], [ns type], [ns name]);
  296. NSLog(@"Error Dict: %@", errorDict);
  297. }
  298. @end