I have to write a TCP Server for my legacy application (standalone) to create a client - server interface for it.
I am planning to write pre-forked (can't user threads because of thread safety issues) concurrent server. I need following two things.
Q. A simple example program (may be an echo-server) explaining concerns and ingredients of a pre-forked concurrent server.
Q. Server will exchange data in JSON format. How to configure client socket, so that server know properly whether the client has completely written the json on channel or it is still in the process of writing.
Why use threads or forks? Just use Tcl's event-driven model.
proc accept {sock host port} {
fconfigure $sock -blocking 0 -buffering line
fileevent $sock readable [list readsock $sock]
}
proc readsock {sock} {
global sockbuf
if {[read $sock data] < 0} {
if {[eof $sock]} {
# Socket was closed by remote
unset sockbuf($sock)
close $sock
return
}
}
append sockbuf($sock) $data\n
# Check if you got all the necessary data. For Tcl lists, use [info complete]
if {[info complete $sockbuf($sock)]} {
set data $sockbuf($sock)
unset sockbuf($sock)
# process data
puts $sock $data
}
}
socket -server accept 12345
vwait forever; # This will enter the event loop.
If you really need (or want) to use Threads, thread safety is also not a problem in Tcl.
But using forks usually end up in reimplementing more or less the thread API.
If you really want to fork, then here are some of the problems that you will encounter:
You have to communicate with the children. I suggest using pipes.
You have to pass the socket from the master to the other children. While this might be possible with unix domain sockets at C level, but I don't know about any Tcl extension that can do that.
You have to write the pool stuff yourself (or use a C library for that).
IMHO it is not worth all the needed effort for forks.
Related
I tried to write a code in TCL. The idea is to write code that does a proxy over cisco. My cisco is cisco 3700 version 12.4 and the version of TCL is 8.3. I work with GNS (Graphical Network Simulator), therefore all components are virtual(including the cisco).
In my code I opened 2 sockets with two diffrent computers: sock1 and sock2.
I configured these sockets in the following way:
fconfigure $sock1 -translation binary -buffering none -blocking 0
fconfigure $sock2 -translation binary -buffering none -blocking 0
Now I tried to transfer information between them (proxy).
As I read, the language is single-threaded and therefore I need to use events. So, I created two file event handlers that called a function:
fileevent $sock1 readable [list proxy $sock1 $sock2]
fileevent $sock2 readable [list proxy $sock2 $sock1]
The proxy function read data from the first socket and send it to the other socket.
The code works well: I transfred rdp and smb over this proxy. The problem is that it really slow: It takes something like 1000-1100 ms. Therefore I can't use remote desktop througth the proxy and even smbclient is very slow. The proxy function is really fast (I checked it and also I tried to print at the start and at the end of the function). Therefore, I assume that the interrupts from the os are very slow (or tcl executes the script slow). In addition I opened wireshark on both sides of the cisco and it takes second between the incoming message and the outgoing message.
Another information:
I want that some clients will communicate at the same time, therefore my TCL code defines a server socket:
set server_socket [socket -server handle_conn $port]
vwait is_finish
and the function "handle_conn" opens socket to the second side and create file event handlers:
proc handle_conn{sock1 addr port} {
CREATE THE SECOND SOCKET (sock2)
fileevent $sock1 readable [list proxy $sock1 $sock2]
fileevent $sock2 readable [list proxy $sock2 $sock1]
}
Therefore, I need asynchronous code (I tried to write a synchronous version: it works fast but the problem is that I can't create more than one connection at the same time (and for example my proxy doesn't work with program that need two ports or with two diffrent programs at the same time)).
I can't understand if the problem is with fconfigure, with events in tcl, with gns or another problem.
Hope for help!
Edit:
proc proxy {s1 s2} {
if {([eof $s1] || [eof $s2]) || ([catch {read $s1} data] || [catch {puts -nonewline $s2 $data}])} {
catch {close $s1}
catch {close $s2}
}
I find it curious that the code is slow for you; Tcl's fast enough to be used to implement full web servers handling complex content. It makes me suspect that something else is going on. For example, the proxy command sounds like it is mainly just copying bytes from one channel to another, but there are slow ways to do this and there are fast ways. One of the best methods is to put both channels in binary mode (fconfigure $chan -translation binary) and then use fcopy in asynchronous mode to move the bytes over; it has been internally optimised to use efficient buffer sizes and limit the amount of copying between memory buffers. Here's how a proxy command might look:
proc proxy {sourceChannel destinationChannel} {
fconfigure $sourceChannel -translation binary
fconfigure $destinationChannel -translation binary
fcopy $sourceChannel $destinationChannel -command [list \
copydone $sourceChannel $destinationChannel]
}
The copydone procedure gets called when everything is moved. Here's a basic example, but you might need to be a bit more careful since you've got copies going in both directions:
proc copydone {src dst numBytes {errorMsg ""}} {
# $numBytes bytes of data were moved
close $src
close $dst
if {$error != ""} {
puts stderr "error in fcopy: $error"
}
}
If it wasn't for the fact that you are running on a cisco device, I'd also suggest upgrading the version of Tcl in use. Formally, 8.3 hasn't been supported for a very long time.
I'm Implementing a custom transport layer protocol on top of UDP to provide robust delivery services and need to ensure proper memory management. I'm trying to use TCP as a reference and see how the function tcp_sendmsg() handles memory constraints.
In the kernel code for tcp_sendmsg(),
if (!sk_stream_memory_free(sk))
goto wait_for_sndbuf;
wait_for_sndbuf:
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
So the SOCK_NOSPACE flag is set for the socket. But how and where is the bit cleared later? And how does the tcp_sendmsg() function know that the bit has been cleared and it can resume sending the data?
Edit 1: As suggested by Maxim in his answer, the function sk_stream_wait_memory() handles the waiting for TCP. Can my protocol, which is built on top of UDP, use this "stream" function as well?
So the SOCK_NOSPACE flag is set for the socket. But how and where is the bit cleared later?
This bit is cleared when the data has been copied (or dropped) from the outgoing socket buffer into the outgoing queue of the device by the queueing discipline.
And how does the tcp_sendmsg() function know that the bit has been cleared and it can resume sending the data?
There is while (msg_data_left(msg)) loop with sk_stream_wait_memory call in it. sk_stream_wait_memory does the waiting.
I'm trying to understand the idea of non-blocking web server and it seems like there is something I miss.
I can understand there are several reasons for "block" web request(psuedocode):
CPU bound
string on_request(arg)
{
DO_SOME_HEAVY_CPU_CALC
return "done";
}
IO bound
string on_request(arg)
{
DO_A_CALL_TO_EXTERNAL_RESOURCE_SUCH_AS_WEB_IO
return "done";
}
sleep
string on_request(arg)
{
sleep(VERY_VERY_LONG_TIME);
return "done";
}
are all the three can benefit from non-blocking server?
how the situation that do benefit from the non-blocking web server really do that?
I mean, when looking at the Tornado server documentation, it seems
like it "free" the thread. I know that a thread can be put to sleep
and wait for a signal from the operation system (at least in Linux),
is this the meaning of "freeing" the thread? is this some higher
level implementation? something that actually create a new thread
that is waiting for new request instead of the "sleeping" one?
Am I missing something here?
Thanks
Basically the way the non-blocking sockets I/O work is by using polling and the state machine. So your scheme for many connections would be something like that:
Create many sockets and make them nonblocking
Switch the state of them to "connect"
Initiate the connect operation on each of them
Poll all of them until some events fire up
Process the fired up events (connection established or connection failed)
Switch the state those established to "sending"
Prepare the Web request in a buffer
Poll "sending" sockets for WRITE operation
send the data for those who got the WRITE event set
For those which have all the data sent, switch the state to "receiving"
Poll "receiving" sockets for READ operation
For those which have the READ event set, perform read and process the read data according to the protocol
Repeat if the protocol is bidirectional, or close the socket if it is not
Of course, at each stage you need to handle errors, and that the state of each socket is different (one may be connecting while another may be already reading).
Regarding polling I have posted an article about how different polling methods work here: http://www.ulduzsoft.com/2014/01/select-poll-epoll-practical-difference-for-system-architects/ - I suggest you check it.
To benefit from a non-blocking server, your code must also be non-blocking - you can't just run blocking code on a non-blocking server and expect better performance. For example, you must remove all calls to sleep() and replace them with non-blocking equivalents like IOLoop.add_timeout (which in turn involves restructuring your code to use callbacks or coroutines).
How To Use Linux epoll with Python http://scotdoyle.com/python-epoll-howto.html may give you some points about this topic.
I am writing a Client/Server application in C++ with the help of Boost Asio. I have a working server, and the server workflow is something I understand well.
My client application handles the connect gracefully as shown in Asio examples, after which, it exchanges a handshake with the server. After that however, the users should be able to send requests to the server when and how they want, which is where I have a problem understanding the paradigm.
The initial workflow goes like a little like this:
OnConnected() { SendHandshake() }
SendHandshake() { async.write_some(handshake...), async_read_some(&OnRead) }
OnRead() { ReadServerHandshake() *** }
And users would send messages by using Write(msg):
Write (msg) { async_write_some(msg,&OnWrite), async_Read_some(&OnRead) }
OnWrite() {}
EDIT: Rephrasing the question to be clearer, here is the scenario:
After the initial handshaking is complete, the Client is only used to send requests to the server, on which it will get a reply. So, for instance, a user sends a write. Client waits for the read operation to complete, reads the reply and does something with it. The next user write will only come after, say, 5 minutes. Will the io_service stop working in the meanwhile because there are no outstanding asynchronous operations in between the last reply read and the next write?
On an informative note, you can provide it with io_service::work to stop an io_service from running out of work. This will ensure that the io_service::run never returns until the work object is destroyed.
To control the lifetime of the work object, you can use a shared_ptr pointer and reset it once the work is done, or you can use boost::optional as outlined here.
Of course you still need to handle the case where either the server closes the TCP connection, or the connection dies for whatever reason. To handle this case, one solution would be to have an outstanding async_read on the socket to the server. The read handler should be called with an error_code when/if something goes wrong with the connection. If you have the outstanding read on the connection, you do not need to use the work object.
If you want the IO service to complete a read, you must start a read. If you want to read data any time the client sends it, you must have an asynchronous read operation pending at all times. Otherwise, how would the library know what to do with the data?
Is there a way to only close "one end" of a TCP socket to cleanly indicate one side of a connection is done writing to the connection? (Just like you do with a pipe in every Unix pipe tutorial ever.) Or should I use some in-band solution like a sentinel value or some such?
You can shutdown a socket for read or write using the second parameter to the method:
shutdown(sock, SHUT_RD)
shutdown(sock, SHUT_WR)
If the server is doing the writing, and does a shutdown() for write, the client should get an end of file when it tries to read (rather than blocking and waiting for data to arrive). It will however still be able to write to the socket.