Re: Simultaneous read() and write() on same TCP/IP socket
Re: Simultaneous read() and write() on same TCP/IP socket
- Subject: Re: Simultaneous read() and write() on same TCP/IP socket
- From: Jonathon Kuo <email@hidden>
- Date: Fri, 31 Dec 2010 12:09:44 -0800
On Dec 14, 2010, at 1:10 AM, Quinn The Eskimo! wrote:
> If you're still working on the socket-to-socket bridging code, I recommend you look at non-blocking sockets with GCD. That's how I'd tackle this problem on modern Apple OSes.
Taking Quinn's advice, I've implemented my message receiver / forwarder using GCD, blocks, and TCP sockets. Everything works!! Sockets get closed when clients depart, new connections get established on new threads when clients connect, etc. I really didn't expect it to all just work. GCD and blocks are really slick!
However... there is one not so small problem.
Once a client connects, the program is waiting on a read() for a message from the client, it takes up about 100% of 1 cpu just sitting there, idle. If two clients are 'connected' such that the program has two GCD threads waiting on read()s, it takes 200% cpu, etc. In the debugger, the thread(s) that are taking all the cpu are:
<com.apple.main-thread>
0 mach_msg_trap
1 mach_msg
2 _CFRunLoopRun
3 CFRunLoopRunSpecific
4 -[NSRunLoop(NSRunLoop) runMode:beforeDate:]
5 -[NSRunLoop(NSRunLoop) run]
6 main
I've profiled the program in Instruments, but it just shows this same thread (one per read() call) taking up 30% the cpu, a kevent thread taking up 30%, and a read() thread taking up 30%. These last two thread backtraces end in _dispatch_worker_thread2.
I've attached the flow of the code below. Perhaps I'm doing something very obviously wrong?
Thanks!
-Jon
---------------------------------------
main.m
[[myobj alloc] init];
[myobj startProcessing];
[[NSRunLoop currentRunLoop] run];
---------------------------------------
[myobj startProcessing]
listensocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); // set up socket
setsockopt(listensocket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)); // set it nohang
fcntl(listensocket,F_SETFL,O_NONBLOCK); // set it non-blocking
bind(listensocket,(struct sockaddr *)&listen_addrin,sizeof(listen_addrin)); // bind the socket
listen(listensocket,5); // set to listen mode
dispatch_source_t lstn_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,listensocket,0,globalQueue);
dispatch_source_set_event_handler((dispatch_source_t)lstn_src, ^{
new_socket = accept(listensocket,(struct sockaddr *)&temp_addrin,&temp_len); // wait for incoming cnx
setsockopt(new_socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)); // set new socket to nohang
fcntl(new_socket,F_SETFL,O_NONBLOCK); // set it to non-blocking
[self processNewConnection]; // invoke method below
});
dispatch_resume(lstn_src);
[myobj processNewConnection]
dispatch_source_t newsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,new_socket,0,globalQueue );
dispatch_source_set_event_handler(newsrc, ^{
for(;;) {
read(new_socket,inbox,&bsize); // read from the socket
// prepare response
write(new_socket,outbuf,baize); // write to the socket
}
dispatch_source_cancel(newsrc);
return;
}); // dispatch
dispatch_source_set_cancel_handler(newsrc, ^{
close(new_socket);
dispatch_release(newsrc);
});
dispatch_resume(newsrc);
---------------------------------------
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Macnetworkprog mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden