I want to set up an application which recieves data on a TCP port (2001).
Are there sample scripts for that, because I can't seem to get it working
with the man pages..
Pat.
Cameron Laird <Cam...@Lairds.com>
Business: http://www.Phaseit.net
Personal: http://starbase.neosoft.com/~claird/home.html
# Open the server socket:
set sock [socket -server accept 2001]
# This proc is called each time a new connection is made:
proc accept {sock addr port} {
puts "Connection $sock from ${addr}:$port"
# Set up fileevents here to read data from the port, or
# just read directly.
fconfigure $sock -blocking 0
# uncomment the following for binary data:
#fconfigure $sock -translation binary -encoding binary
fileevent $sock readable [list readData $sock]
}
# This is called every time data is available on a connection:
proc readData {sock} {
# Read data from a socket when available
puts "Reading data from $sock"
if {[catch {gets $sock} line] || [eof $sock]} {
puts "socket closed"
catch {close $sock}
# I'm not sure if this bit is needed, but better
# on the safe side:
if {[string length $line]} {
puts "Last bit of data: $line"
}
} else {
puts "Read $line from $sock"
}
}
vwait forever; # only needed in tclsh
Regards, Pat.
Bruce
proc Open_conn {} {
set sock [socket -server accept 20001]
.time.status.label2 configure -text "Connection $sock "
# Set up fileevents here to read data from the port, or
# just read directly.
fconfigure $sock -blocking 0
# uncomment the following for binary data:
#fconfigure $sock -translation binary -encoding binary
fileevent $sock readable [list readData $sock]
}
With the fileevent, wish calls an error..
Yep, you missed a step. You are trying to read from the server socket itself.
The socket returned from the [socket -server ...] command is ONLY for accepting connections
no I/O occurs on it. When a new connection is received, the specified proc (in this case accept)
is called with 3 arguments - the first one being a socket that is opened for I/O - this is the socket
you need to fconfigure and setup the fileevent on.
Bruce
OKe... but what do I have to change to do that?
I can't see the difference with the code Neil gave. Could you give me a hint
here.
(it is obvious that I have only used file i/o with tcl).
Thanx,
pat
Look again at Neil's example: the sock returned from the [socket -server ..] command
is NEVER used. (You might want to save it off in case you want to close it to stop
accepting new connections, but other than that you don't really need it).
the key is that the first param to the socket command after the -server switch is a proc
name that is called each time a new connection is made (in Neil's example it was called
accept, but it can be any name you want) This proc is called with 3 args - the new socket
that was created for the connection, the address of the other end and the port on the other
end - it is inside this proc that the configuration of the socket is done - in your code you
never defined the accept proc - so when a new connection was attempted you would have
got an error about accept not being defined, but then you tried to configure your server socket
for I/O, which is a no-no.
On the server side the initial socket created is ONLY for accepting connections - not I/O.
Each new connection will automatically create a new socket for I/O and there can be multiple
of these open at the same time (up to some system limit of descriptors)
Once you get it, sockets in tcl are so simple (try any of this at the C level and it is unbelievable
how hard it is to do these simple things)
Bruce
Network communication indeed is one of the glories of the
Tcl library.
Let's make this concrete. Here's what I regard as a canonical
example C-coded simple server example:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#define LISTEN_LIMIT 20
#define SERVICE_PORT 3364
void simple_response(int );
int main(int argc, char **argv)
{
int listenfd, connfd;
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERVICE_PORT);
bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
listen(listenfd, LISTEN_LIMIT);
while (TRUE) {
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
if ((childpid = fork()) == 0) {
close(listenfd);
simple_response(connfd);
exit(0);
}
close(connfd);
}
}
#define MAXLINE 80
/********
*
* In this example, echo the characters of the query back,
* reversed.
*
********/
void simple_response(int sockfd)
{
char line[MAXLINE], *ptr;
FILE *fpin, *fpout;
fpin = fdopen(sockfd, "r");
fpout = fdopen(sockfd, "w");
while (1) {
if (fgets(line, MAXLINE, fpin) == NULL)
return;
for (ptr = line + strlen(line) - 2; ptr >= line; ptr--)
putc(*ptr, fpout);
putc('\n', fpout);
fflush(fpout);
}
}
Judge for yourself how this compares to Tcl in readability
and maintainability.
One point that I think deserves emphasis, though, is Tcl's
remarkable portability. That simple little TCP/IP server
Bruce has been explaining works correctly under MacOS, OpenVMS,
Unix, and Win*. The C stuff above ... while, different C
libraries require select(), or poll(), or threading, in
place of fork() as a concurrency mechanism. Enjoy Tcl,
folks.
Wow!!! I finally got it working. Thanks a lot guys, for the help and for
your patience...
Pat.