mirror of
https://github.com/gnustep/libs-gsweb.git
synced 2025-02-21 02:41:04 +00:00
* GSWeb/GSWDictionary.m
added - dealloc * GSWeb/GSWDefaultAdaptor.h * GSWeb/GSWDefaultAdaptor.m * GSWeb/GSWWorkerThread.h * GSWeb/GSWWorkerThread.m pooling NSThreads now to make GSW able to handle multiple threads.
This commit is contained in:
parent
143b590b70
commit
e108560e37
5 changed files with 181 additions and 128 deletions
3
GSWeb/GSWDefaultAdaptor.h
Normal file → Executable file
3
GSWeb/GSWDefaultAdaptor.h
Normal file → Executable file
|
@ -95,7 +95,8 @@ GSWEB_EXPORT int iBlock;
|
||||||
-(BOOL)isConnectionAllowedWithHandle:(NSFileHandle*)handle
|
-(BOOL)isConnectionAllowedWithHandle:(NSFileHandle*)handle
|
||||||
returnedMessage:(NSString**)retMessage;
|
returnedMessage:(NSString**)retMessage;
|
||||||
|
|
||||||
- (void) workerThreadWillExit:(GSWWorkerThread*) thread;
|
// GSW only
|
||||||
|
- (void) workerThreadFinished:(GSWWorkerThread*) thread;
|
||||||
|
|
||||||
-(void)stop;
|
-(void)stop;
|
||||||
-(void)run;
|
-(void)run;
|
||||||
|
|
78
GSWeb/GSWDefaultAdaptor.m
Normal file → Executable file
78
GSWeb/GSWDefaultAdaptor.m
Normal file → Executable file
|
@ -104,9 +104,21 @@ static GSWResponse * static_lastDitchErrorResponse = nil;
|
||||||
ASSIGN(_adaptorHost,[arguments objectForKey:GSWOPT_AdaptorHost[GSWebNamingConv]]);
|
ASSIGN(_adaptorHost,[arguments objectForKey:GSWOPT_AdaptorHost[GSWebNamingConv]]);
|
||||||
|
|
||||||
if ((_workerThreadCountMax <1) || (_isMultiThreadEnabled == NO)) {
|
if ((_workerThreadCountMax <1) || (_isMultiThreadEnabled == NO)) {
|
||||||
_workerThreadCountMax = 1;
|
_workerThreadCountMax = 0;
|
||||||
_isMultiThreadEnabled = NO;
|
_isMultiThreadEnabled = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_isMultiThreadEnabled) {
|
||||||
|
for (int i=0; i < _workerThreadCountMax; i++) {
|
||||||
|
GSWWorkerThread * thread = [GSWWorkerThread alloc];
|
||||||
|
thread = [thread initWithApp:GSWApp
|
||||||
|
adaptor:self
|
||||||
|
stream:nil];
|
||||||
|
[_threads addObject: thread];
|
||||||
|
[thread release];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -187,18 +199,16 @@ void _queueWorkOnHandle(NSFileHandle* handle, NSMutableArray* waitingThreadArray
|
||||||
atIndex: [waitingThreadArray count]];
|
atIndex: [waitingThreadArray count]];
|
||||||
}
|
}
|
||||||
|
|
||||||
// never called if single threaded.
|
|
||||||
- (void) workerThreadWillExit:(GSWWorkerThread*) thread
|
- (void) workerThreadFinished:(GSWWorkerThread*) thread
|
||||||
{
|
{
|
||||||
[_selfLock lock];
|
[_selfLock lock];
|
||||||
[thread retain];
|
if ([_waitingThreads count]) {
|
||||||
[_threads removeObject: thread];
|
[thread setServerSocket:[_waitingThreads objectAtIndex:0]];
|
||||||
if ([_waitingThreads count]) {
|
[_waitingThreads removeObjectAtIndex:0];
|
||||||
_workOnHandle([_waitingThreads objectAtIndex:0], self, _threads, _isMultiThreadEnabled);
|
}
|
||||||
[_waitingThreads removeObjectAtIndex:0];
|
|
||||||
}
|
|
||||||
[thread autorelease];
|
|
||||||
[_selfLock unlock];
|
[_selfLock unlock];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//PRIVATE!
|
//PRIVATE!
|
||||||
|
@ -268,44 +278,54 @@ void _queueWorkOnHandle(NSFileHandle* handle, NSMutableArray* waitingThreadArray
|
||||||
return GSWIntNumber(_workerThreadCount);
|
return GSWIntNumber(_workerThreadCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use locked only
|
||||||
|
- (GSWWorkerThread*) _nextFreeThread
|
||||||
|
{
|
||||||
|
for (GSWWorkerThread *thread in _threads) {
|
||||||
|
if ([thread isWorking] == NO) {
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
-(void)announceNewConnection:(NSNotification*)notification
|
-(void)announceNewConnection:(NSNotification*)notification
|
||||||
{
|
{
|
||||||
NSFileHandle *listenHandle=nil;
|
NSFileHandle *listenHandle=nil;
|
||||||
NSFileHandle *inStream = nil;
|
NSFileHandle *inStream = nil;
|
||||||
NSString* connRefusedMessage=nil;
|
NSString* connRefusedMessage=nil;
|
||||||
|
|
||||||
// requestTS=GSWTime_now();
|
|
||||||
|
|
||||||
listenHandle=[notification object];
|
listenHandle=[notification object];
|
||||||
|
|
||||||
inStream = [[notification userInfo] objectForKey:@"NSFileHandleNotificationFileHandleItem"];
|
inStream = [[notification userInfo] objectForKey:@"NSFileHandleNotificationFileHandleItem"];
|
||||||
// we want future Notifications.
|
// we want future Notifications.
|
||||||
[listenHandle acceptConnectionInBackgroundAndNotify];
|
[listenHandle acceptConnectionInBackgroundAndNotify];
|
||||||
|
|
||||||
|
|
||||||
if (![self isConnectionAllowedWithHandle:inStream
|
if (![self isConnectionAllowedWithHandle:inStream
|
||||||
returnedMessage:&connRefusedMessage]) {
|
returnedMessage:&connRefusedMessage]) {
|
||||||
// don't waste any time
|
// don't waste any time
|
||||||
[inStream closeFile];
|
[inStream closeFile];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SYNCHRONIZED(_selfLock)
|
|
||||||
{
|
|
||||||
[_selfLock lock];
|
[_selfLock lock];
|
||||||
int count = [_threads count];
|
|
||||||
|
GSWWorkerThread * thread = nil;
|
||||||
if (count < _workerThreadCountMax) {
|
|
||||||
_workOnHandle(inStream,self, _threads, _isMultiThreadEnabled);
|
if (_isMultiThreadEnabled) {
|
||||||
|
thread = [self _nextFreeThread];
|
||||||
|
|
||||||
|
if (thread) {
|
||||||
|
[thread setServerSocket:inStream];
|
||||||
} else {
|
} else {
|
||||||
_queueWorkOnHandle(inStream, _waitingThreads);
|
_queueWorkOnHandle(inStream, _waitingThreads);
|
||||||
}
|
}
|
||||||
[_selfLock unlock];
|
|
||||||
|
} else {
|
||||||
|
_workOnHandle(inStream,self, _threads, _isMultiThreadEnabled);
|
||||||
}
|
}
|
||||||
|
[_selfLock unlock];
|
||||||
// END_SYNCHRONIZED;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-(NSFileHandle*)fileHandle
|
-(NSFileHandle*)fileHandle
|
||||||
|
@ -414,7 +434,7 @@ void _queueWorkOnHandle(NSFileHandle* handle, NSMutableArray* waitingThreadArray
|
||||||
// CHECKME: find out if we really need this. -- dw
|
// CHECKME: find out if we really need this. -- dw
|
||||||
-(id)workerThreadCountMax
|
-(id)workerThreadCountMax
|
||||||
{
|
{
|
||||||
return [NSNumber numberWithInt:1000];
|
return [NSNumber numberWithInt:_workerThreadCountMax];
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECKME: find out if we really need this. -- dw
|
// CHECKME: find out if we really need this. -- dw
|
||||||
|
|
7
GSWeb/GSWDictionary.m
Normal file → Executable file
7
GSWeb/GSWDictionary.m
Normal file → Executable file
|
@ -35,6 +35,13 @@
|
||||||
|
|
||||||
@implementation GSWDictionary
|
@implementation GSWDictionary
|
||||||
|
|
||||||
|
-(void) dealloc
|
||||||
|
{
|
||||||
|
DESTROY(_storageDict);
|
||||||
|
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
+ (instancetype) dictionary
|
+ (instancetype) dictionary
|
||||||
{
|
{
|
||||||
return AUTORELEASE([[self alloc] init]);
|
return AUTORELEASE([[self alloc] init]);
|
||||||
|
|
5
GSWeb/GSWWorkerThread.h
Normal file → Executable file
5
GSWeb/GSWWorkerThread.h
Normal file → Executable file
|
@ -71,15 +71,18 @@
|
||||||
// int _inputBufferIndex;
|
// int _inputBufferIndex;
|
||||||
// BOOL _keepAlive;
|
// BOOL _keepAlive;
|
||||||
// BOOL _errorOnRead;
|
// BOOL _errorOnRead;
|
||||||
// BOOL _runFlag;
|
NSCondition * _queueCondition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setServerSocket:(NSFileHandle*)stream;
|
||||||
|
|
||||||
-(id)initWithApp:(GSWApplication*)application
|
-(id)initWithApp:(GSWApplication*)application
|
||||||
adaptor:(GSWAdaptor*)adaptor
|
adaptor:(GSWAdaptor*)adaptor
|
||||||
stream:(NSFileHandle*)stream;
|
stream:(NSFileHandle*)stream;
|
||||||
|
|
||||||
-(void)runOnce;
|
-(void)runOnce;
|
||||||
|
|
||||||
|
-(BOOL)isWorking;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
216
GSWeb/GSWWorkerThread.m
Normal file → Executable file
216
GSWeb/GSWWorkerThread.m
Normal file → Executable file
|
@ -32,16 +32,12 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "GSWWOCompatibility.h"
|
#include "GSWWOCompatibility.h"
|
||||||
|
|
||||||
#include "GSWWorkerThread.h"
|
#include "GSWWorkerThread.h"
|
||||||
|
|
||||||
|
|
||||||
#include "GSWPrivate.h"
|
#include "GSWPrivate.h"
|
||||||
#include "GSWDefines.h"
|
#include "GSWDefines.h"
|
||||||
#include "GSWConstants.h"
|
#include "GSWConstants.h"
|
||||||
#include "GSWUtils.h"
|
#include "GSWUtils.h"
|
||||||
#include "GSWDebug.h"
|
#include "GSWDebug.h"
|
||||||
|
|
||||||
#include "GSWRequest.h"
|
#include "GSWRequest.h"
|
||||||
#include "GSWApplication.h"
|
#include "GSWApplication.h"
|
||||||
#include "GSWAdaptor.h"
|
#include "GSWAdaptor.h"
|
||||||
|
@ -49,28 +45,31 @@
|
||||||
#include "GSWResponse.h"
|
#include "GSWResponse.h"
|
||||||
#include "GSWHTTPIO.h"
|
#include "GSWHTTPIO.h"
|
||||||
|
|
||||||
//static NSData* lineFeedData=nil;
|
|
||||||
static NSString *REQUEST_ID = @"x-webobjects-request-id";
|
static NSString *REQUEST_ID = @"x-webobjects-request-id";
|
||||||
|
|
||||||
@interface NSThread (WeKnowWhatWeDo)
|
|
||||||
- (void)run;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@implementation GSWWorkerThread
|
@implementation GSWWorkerThread
|
||||||
|
|
||||||
+ (void) initialize
|
+ (void) initialize
|
||||||
{
|
{
|
||||||
if (self == [GSWWorkerThread class])
|
if (self == [GSWWorkerThread class])
|
||||||
{
|
{
|
||||||
// ASSIGN(lineFeedData,([[NSString stringWithString:@"\n"] dataUsingEncoding:NSASCIIStringEncoding]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setServerSocket:(NSFileHandle*)stream
|
||||||
|
{
|
||||||
|
[_queueCondition lock];
|
||||||
|
ASSIGN(_serverSocket,stream);
|
||||||
|
[_queueCondition signal];
|
||||||
|
[_queueCondition unlock];
|
||||||
|
}
|
||||||
|
|
||||||
-(void)dealloc
|
-(void)dealloc
|
||||||
{
|
{
|
||||||
// TODO: add vars!
|
// TODO: add vars!
|
||||||
DESTROY(_serverSocket);
|
DESTROY(_serverSocket);
|
||||||
DESTROY(_currentSocket);
|
DESTROY(_currentSocket);
|
||||||
|
DESTROY(_queueCondition);
|
||||||
_app = nil;
|
_app = nil;
|
||||||
_mtAdaptor = nil;
|
_mtAdaptor = nil;
|
||||||
|
|
||||||
|
@ -82,40 +81,37 @@ static NSString *REQUEST_ID = @"x-webobjects-request-id";
|
||||||
adaptor:(GSWAdaptor*)adaptor
|
adaptor:(GSWAdaptor*)adaptor
|
||||||
stream:(NSFileHandle*)stream
|
stream:(NSFileHandle*)stream
|
||||||
{
|
{
|
||||||
if ((self = [self init])) {
|
if ((self = [self init])) {
|
||||||
_app = application;
|
_runFlag = NO;
|
||||||
_mtAdaptor = (GSWDefaultAdaptor*)adaptor;
|
_app = application;
|
||||||
ASSIGN(_serverSocket,stream);
|
_mtAdaptor = (GSWDefaultAdaptor*)adaptor;
|
||||||
_keepAlive=NO;
|
ASSIGN(_serverSocket,stream);
|
||||||
_maxSocketIdleTime=900; // 300 ms
|
_keepAlive=NO;
|
||||||
_isMultiThreadEnabled = [adaptor isMultiThreadEnabled];
|
_maxSocketIdleTime=900; // 300 ms
|
||||||
|
_isMultiThreadEnabled = [adaptor isMultiThreadEnabled];
|
||||||
if (_isMultiThreadEnabled) {
|
|
||||||
_t = [[NSThread alloc] initWithTarget:self
|
if (_isMultiThreadEnabled) {
|
||||||
selector:@selector(runOnce)
|
_queueCondition = [[NSCondition alloc] init];
|
||||||
object:nil];
|
|
||||||
|
_t = [[NSThread alloc] initWithTarget:self
|
||||||
[[NSNotificationCenter defaultCenter] addObserver: self
|
selector:@selector(checkForWork)
|
||||||
selector:@selector(threadWillExit:)
|
object:nil];
|
||||||
name:NSThreadWillExitNotification
|
|
||||||
object: _t];
|
[_t start];
|
||||||
_runFlag = YES;
|
[_t autorelease];
|
||||||
[_t start];
|
} else {
|
||||||
[_t autorelease];
|
_runFlag = YES;
|
||||||
} else {
|
_pool = [[NSAutoreleasePool alloc] init];
|
||||||
_runFlag = YES;
|
[self runOnce];
|
||||||
_pool = [[NSAutoreleasePool alloc] init];
|
DESTROY(_pool);
|
||||||
[self runOnce];
|
|
||||||
DESTROY(_pool);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return self;
|
|
||||||
|
}
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)threadWillExit:(NSNotification*)notification
|
- (void)threadWillExit:(NSNotification*)notification
|
||||||
{
|
{
|
||||||
[_mtAdaptor workerThreadWillExit:self];
|
|
||||||
_mtAdaptor = nil;
|
_mtAdaptor = nil;
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver: self];
|
[[NSNotificationCenter defaultCenter] removeObserver: self];
|
||||||
}
|
}
|
||||||
|
@ -130,70 +126,91 @@ static NSString *REQUEST_ID = @"x-webobjects-request-id";
|
||||||
_currentSocket = nil;
|
_currentSocket = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) checkForWork
|
||||||
|
{
|
||||||
|
while (![[NSThread currentThread] isCancelled]) {
|
||||||
|
[_queueCondition lock];
|
||||||
|
[_queueCondition wait];
|
||||||
|
|
||||||
|
if (_serverSocket == nil) {
|
||||||
|
[_queueCondition unlock];
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
_runFlag = YES;
|
||||||
|
}
|
||||||
|
[_queueCondition unlock];
|
||||||
|
_pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
[self runOnce];
|
||||||
|
DESTROY(_pool);
|
||||||
|
DESTROY(_serverSocket);
|
||||||
|
[_mtAdaptor workerThreadFinished:self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
-(void)runOnce
|
-(void)runOnce
|
||||||
{
|
{
|
||||||
GSWRequest *request = nil;
|
GSWRequest *request = nil;
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
GSWResponse *response;
|
GSWResponse *response;
|
||||||
|
|
||||||
|
if ((!_runFlag) || (_serverSocket == nil)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_errorOnRead = NO;
|
||||||
|
// _maxSocketIdleTime is milisecs!
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
timeout.tv_usec = _maxSocketIdleTime * 1000;
|
||||||
|
|
||||||
|
NS_DURING {
|
||||||
|
setsockopt([_serverSocket fileDescriptor], SOL_SOCKET, SO_RCVTIMEO, &timeout,sizeof(timeout));
|
||||||
|
|
||||||
if ((!_runFlag) || (_serverSocket == nil)) {
|
request = [GSWHTTPIO readRequestFromFromHandle: _serverSocket];
|
||||||
return;
|
} NS_HANDLER {
|
||||||
|
_errorOnRead = YES;
|
||||||
|
NSLog(@"%s -- dropping connection reason: %@",__PRETTY_FUNCTION__, [localException reason]);
|
||||||
|
} NS_ENDHANDLER;
|
||||||
|
|
||||||
|
// "womp" is the request handler key used by the WOTaskD contacing your app
|
||||||
|
if ((_errorOnRead || (request == nil)) ||
|
||||||
|
((([[_app class] isDirectConnectEnabled] == NO) && ([request isUsingWebServer] == NO)) &&
|
||||||
|
([@"womp" isEqual:[request requestHandlerKey]] == NO))) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
_processingRequest = YES;
|
||||||
|
_dispatchError = NO;
|
||||||
|
|
||||||
|
NS_DURING {
|
||||||
|
response = [_app dispatchRequest:request];
|
||||||
|
} NS_HANDLER {
|
||||||
|
NSLog(@"%s -- Exception occurred while responding to client: %@",
|
||||||
|
__PRETTY_FUNCTION__, [localException description]);
|
||||||
|
_dispatchError = YES;
|
||||||
|
response = [GSWDefaultAdaptor _lastDitchErrorResponse];
|
||||||
|
} NS_ENDHANDLER;
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
NSString * reqid = [request headerForKey:REQUEST_ID];
|
||||||
|
if (reqid) {
|
||||||
|
[response setHeader:reqid forKey:REQUEST_ID];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_errorOnRead = NO;
|
|
||||||
// _maxSocketIdleTime is milisecs!
|
|
||||||
timeout.tv_sec = 0;
|
|
||||||
timeout.tv_usec = _maxSocketIdleTime * 1000;
|
|
||||||
|
|
||||||
|
|
||||||
NS_DURING {
|
NS_DURING {
|
||||||
setsockopt([_serverSocket fileDescriptor], SOL_SOCKET, SO_RCVTIMEO, &timeout,sizeof(timeout));
|
[GSWHTTPIO sendResponse:response
|
||||||
|
toHandle: _serverSocket
|
||||||
request = [GSWHTTPIO readRequestFromFromHandle: _serverSocket];
|
request:request];
|
||||||
} NS_HANDLER {
|
} NS_HANDLER {
|
||||||
_errorOnRead = YES;
|
NSLog(@"%s -- Exception while sending response: %@",
|
||||||
NSLog(@"%s -- dropping connection reason: %@",__PRETTY_FUNCTION__, [localException reason]);
|
__PRETTY_FUNCTION__, [localException description]);
|
||||||
} NS_ENDHANDLER;
|
} NS_ENDHANDLER;
|
||||||
|
}
|
||||||
// "womp" is the request handler key used by the WOTaskD contacing your app
|
|
||||||
if ((_errorOnRead || (request == nil)) ||
|
|
||||||
((([[_app class] isDirectConnectEnabled] == NO) && ([request isUsingWebServer] == NO)) &&
|
|
||||||
([@"womp" isEqual:[request requestHandlerKey]] == NO))) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
_processingRequest = YES;
|
|
||||||
_dispatchError = NO;
|
|
||||||
|
|
||||||
NS_DURING {
|
|
||||||
response = [_app dispatchRequest:request];
|
|
||||||
} NS_HANDLER {
|
|
||||||
NSLog(@"%s -- Exception occurred while responding to client: %@",
|
|
||||||
__PRETTY_FUNCTION__, [localException description]);
|
|
||||||
_dispatchError = YES;
|
|
||||||
response = [GSWDefaultAdaptor _lastDitchErrorResponse];
|
|
||||||
} NS_ENDHANDLER;
|
|
||||||
|
|
||||||
if (response) {
|
|
||||||
NSString * reqid = [request headerForKey:REQUEST_ID];
|
|
||||||
if (reqid) {
|
|
||||||
[response setHeader:reqid forKey:REQUEST_ID];
|
|
||||||
}
|
|
||||||
NS_DURING {
|
|
||||||
[GSWHTTPIO sendResponse:response
|
|
||||||
toHandle: _serverSocket
|
|
||||||
request:request];
|
|
||||||
} NS_HANDLER {
|
|
||||||
NSLog(@"%s -- Exception while sending response: %@",
|
|
||||||
__PRETTY_FUNCTION__, [localException description]);
|
|
||||||
} NS_ENDHANDLER;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
||||||
[self _closeSocket];
|
[self _closeSocket];
|
||||||
|
|
||||||
_processingRequest = NO;
|
_processingRequest = NO;
|
||||||
|
_runFlag = NO;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -209,9 +226,14 @@ done:
|
||||||
|
|
||||||
- (NSString*) description
|
- (NSString*) description
|
||||||
{
|
{
|
||||||
return [NSString stringWithFormat:@"<%s %p socket:%@ >",
|
return [NSString stringWithFormat:@"<%s %p socket:%@ isWorking:%s>",
|
||||||
object_getClassName(self),
|
object_getClassName(self),
|
||||||
(void*)self, _serverSocket];
|
(void*)self, _serverSocket, _runFlag ? "YES" : "NO"];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL)isWorking
|
||||||
|
{
|
||||||
|
return _runFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
Loading…
Reference in a new issue