proc read_data {} {
set sum 0
set count 0
set mask 0x5A
# Choose any host other than the local one, and the difference
# between C and Tcl shrinks even more. 5837 is a port chosen
# merely for convenience.
set channel [socket localhost 5837]
fconfigure $channel -translation binary
while 1 {
set data [read $channel]
foreach item [split $data {}] {
incr count
# In process-control contexts, I often need to mask
# off a few bits and manipulate the resulting value.
# Neither $mask nor the single right-shift are
# particularly meaningful; they're just the results
# of experiments to yield suggestive, quantifiable
# results.
set value [scan $item %c]
set addend [expr {($mask & $value) >> 1}]
incr sum $addend
# puts -nonewline "$value ($addend) "
}
if {[eof $channel]} break
}
puts "\nSum is '[format %x $sum]'."
return $count
}
set result [time {set count [read_data]} 3]
puts $result
# This is a hackish way to extract the time.
set microseconds [lindex $result 0]
set quotient [expr round(double($microseconds) / $count)]
puts "$quotient microseconds per byte received."On a generic Linux x86 host at hand, when I blasted random data from a simple server (see below) as fast as possible, I observed these results. The latter two columns are microseconds per byte received:
Bytes Tcl C
------ --- ---
100 17 36
300 11 14
1000 8 6
10000 6 2
30000 6 2
100000 6 2My summary: don't choose C because of performance. Unless message sizes are quite large, or you're willing to tune your C coding carefully, you can safely assume that Tcl's performance penalty is 60% at most (an amount easily lost in network, UI, and other noise), and possibly far less.Here's a simple C recv-based client:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
void error(char *msg)
{
perror(msg);
exit(0);
}
long int difference(struct timeval *before, struct timeval *after)
{
return 1000000 * (after->tv_sec - before->tv_sec) +
(after->tv_usec - before->tv_usec);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n, byte, rc;
int mask, sum, count, diff, addend;
char *ptr;
struct sockaddr_in serv_addr;
struct hostent *server;
unsigned char buf[512];
struct timeval before, after;
sum = 0;
count = 0;
portno = 5837;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname("localhost");
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd, &serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
mask = 0x5A;
gettimeofday(&before, NULL);
while (1) {
rc = recv(sockfd, buf, sizeof(buf), 0);
if (rc <= 0) break;
for (ptr = buf; rc--;) {
byte = *ptr++;
count++;
addend = (mask & byte) >> 1;
sum += addend;
/* printf("%d (%d) ", byte, addend); */
}
}
printf("\nSum is '%x'.\n", sum);
gettimeofday(&after, NULL);
printf("%ld and %ld.\n", after.tv_sec, after.tv_usec);
diff = difference(&before, &after);
printf("Elapsed time is %d microseconds.\n", diff);
printf("That is %d microseconds per byte received.\n", diff / count);
return 0;
}[Still to do: exhibit model server, and comment on Windows vs. Unix.]
See also:

