OSDN Git Service

Update CocoaAsyncSocket 4.3.5
[syncr/master.git] / CocoaAsyncSocket / CocoaAsyncSocket-4.3.5 / AsyncSocketSample / EchoServerMain.m
1 #import <Foundation/Foundation.h>
2 #import "../AsyncSocket.h"
3
4 #pragma mark Interface
5
6 @interface EchoServer : NSObject
7 {
8         NSMutableArray *sockets;
9 }
10 -(id) init;
11 -(void) dealloc;
12 -(void) acceptOnPortString:(NSString *)str;
13 -(void) onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err;
14 -(void) onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket;
15 -(void) onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port;
16 -(void) onSocket:(AsyncSocket *)sock didReadData:(NSData*)data withTag:(long)tag;
17 -(void) onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag;
18 @end
19
20 #pragma mark -
21 #pragma mark Implementation
22
23 @implementation EchoServer
24
25
26 /*
27  This method sets up the accept socket, but does not actually start it.
28  Once started, the accept socket accepts incoming connections and creates new
29  instances of AsyncSocket to handle them.
30  Echo Server keeps the accept socket in index 0 of the sockets array and adds
31  incoming connections at indices 1 and up.
32 */
33 -(id) init
34 {
35         self = [super init];
36         sockets = [[NSMutableArray alloc] initWithCapacity:2];
37
38         AsyncSocket *acceptor = [[AsyncSocket alloc] initWithDelegate:self];
39         [sockets addObject:acceptor];
40         [acceptor release];
41         return self;
42 }
43
44
45 /*
46  This method will never get called, because you'll be using Ctrl-C to exit the
47  app.
48 */
49 -(void) dealloc
50 {
51         // Releasing a socket will close it if it is connected or listening.
52         [sockets release];
53         [super dealloc];
54 }
55
56
57 /*
58  This method actually starts the accept socket. It is the first thing called by
59  the run-loop.
60 */
61 - (void) acceptOnPortString:(NSString *)str
62 {
63         // AsyncSocket requires a run-loop.
64         NSAssert ([[NSRunLoop currentRunLoop] currentMode] != nil, @"Run loop is not running");
65         
66         UInt16 port = [str intValue];
67         AsyncSocket *acceptor = (AsyncSocket *)[sockets objectAtIndex:0];
68
69         NSError *err = nil;
70         if ([acceptor acceptOnPort:port error:&err])
71                 NSLog (@"Waiting for connections on port %u.", port);
72         else
73         {
74                 // If you get a generic CFSocket error, you probably tried to use a port
75                 // number reserved by the operating system.
76                 
77                 NSLog (@"Cannot accept connections on port %u. Error domain %@ code %d (%@). Exiting.", port, [err domain], [err code], [err localizedDescription]);
78                 exit(1);
79         }
80 }
81
82
83 /*
84  This will be called whenever AsyncSocket is about to disconnect. In Echo Server,
85  it does not do anything other than report what went wrong (this delegate method
86  is the only place to get that information), but in a more serious app, this is
87  a good place to do disaster-recovery by getting partially-read data. This is
88  not, however, a good place to do cleanup. The socket must still exist when this
89  method returns.
90  
91  I do not implement -onSocketDidDisconnect:. Normally, that is where you would
92  release the disconnected socket and perform housekeeping, but I am satisfied
93  to leave the disconnected socket instances alone until Echo Server quits.
94 */
95 -(void) onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
96 {
97         if (err != nil)
98                 NSLog (@"Socket will disconnect. Error domain %@, code %d (%@).",
99                            [err domain], [err code], [err localizedDescription]);
100         else
101                 NSLog (@"Socket will disconnect. No error.");
102 }
103
104
105 /*
106  This method is called when a connection is accepted and a new socket is created.
107  This is a good place to perform housekeeping and re-assignment -- assigning an
108  controller for the new socket, or retaining it. Here, I add it to the array of
109  sockets. However, the new socket has not yet connected and no information is
110  available about the remote socket, so this is not a good place to screen incoming
111  connections. Use onSocket:didConnectToHost:port: for that.
112 */
113 -(void) onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
114 {
115         NSLog (@"Socket %d accepting connection.", [sockets count]);
116         [sockets addObject:newSocket];
117 }
118
119
120 /*
121  At this point, the new socket is ready to use. This is where you can screen the
122  remote socket or find its DNS name (the host parameter is just an IP address).
123  This is also where you should set up your initial read or write request, unless
124  you have a particular reason for delaying it.
125 */
126 -(void) onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
127 {
128         NSLog (@"Socket %d successfully accepted connection from %@ %u.", [sockets indexOfObject:sock], host, port);
129         NSData *newline = [@"\n" dataUsingEncoding:NSASCIIStringEncoding];
130
131         // In Echo Server, each packet consists of a line of text, delimited by "\n".
132         // This is not a technique you should use. I do not know what "\n" actually
133         // means in terms of bytes. It could be CR, LF, or CRLF.
134         //
135         // In your own networking protocols, you must be more explicit. AsyncSocket 
136         // provides byte sequences for each line ending. These are CRData, LFData,
137         // and CRLFData. You should use one of those instead of "\n".
138         
139         // Start reading.
140         [sock readDataToData:newline withTimeout:-1 tag:[sockets indexOfObject:sock]];
141 }
142
143
144 /*
145  This method is called whenever a packet is read. In Echo Server, a packet is
146  simply a line of text, and it is transmitted to the connected Echo clients.
147  Once you have dealt with the incoming packet, you should set up another read or
148  write request, or -- unless there are other requests queued up -- AsyncSocket
149  will sit idle.
150 */
151 -(void) onSocket:(AsyncSocket *)sock didReadData:(NSData*)data withTag:(long)tag
152 {
153         NSString *str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
154
155         // Print string.
156         NSString *trimStr = [str stringByTrimmingCharactersInSet:[NSCharacterSet controlCharacterSet]];
157         [str release];
158         NSLog (@"Socket %d sent text \"%@\".", tag, trimStr);
159
160         // Forward string to other sockets.
161         int i; for (i = 1; i < [sockets count]; ++i)
162                 [(AsyncSocket *)[sockets objectAtIndex:i] writeData:data withTimeout:-1 tag:i];
163
164         // Read more from this socket.
165         NSData *newline = [@"\n" dataUsingEncoding:NSASCIIStringEncoding];
166         [sock readDataToData:newline withTimeout:-1 tag:tag];
167 }
168
169
170 /*
171  This method is called when AsyncSocket has finished writing something. Echo
172  Server does not need to do anything after writing, but your own app might need
173  to wait for a command from the remote application, or begin writing the next
174  packet.
175 */
176 -(void) onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
177 {
178         NSLog (@"Wrote to socket %d.", tag);
179 }
180
181 @end
182
183 #pragma mark -
184 #pragma mark Main
185
186 int main (int argc, const char * argv[])
187 {
188         printf ("ECHO SERVER by Dustin Voss copyright 2003. Sample code for using AsyncSocket.");
189         printf ("\nSYNTAX: %s port", argv[0]);
190         printf ("\nAccepts multiple connections from ECHO clients, echoing any client to all\nclients.\n");
191         if (argc != 2) exit(1);
192         
193         printf ("Press Ctrl-C to exit.\n");
194         fflush (stdout);
195
196         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
197         EchoServer *es = [[EchoServer alloc] init];
198         NSString *portString = [NSString stringWithCString:argv[1]];
199
200         // Here, I use perform...afterDelay to put an action on the run-loop before
201         // it starts running. That action will actually start the accept socket, and
202         // AsyncSocket will then be able to create other activity on the run-loop.
203         // But main() will have no other opportunity to do so; the run-loop does not
204         // give me any way in, other than the AsyncSocket delegate methods.
205
206         // Note that I cannot call AsyncSocket's -acceptOnPort:error: outside of the
207         // run-loop.
208         
209         [es performSelector:@selector(acceptOnPortString:) withObject:portString afterDelay:1.0];
210         [[NSRunLoop currentRunLoop] run];
211         [EchoServer release];
212         [pool release];
213
214         return 0;
215 }