Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

One more socket problem

Status
Not open for further replies.

firelex

Programmer
Jan 10, 2002
118
DE
Hi, all!
Does anybody know if sockets have problems with certain amount of characters?
The situation:
I have opened a socket and created a "read-event" handler which calls a procedure. It works OK. But at certain amount of characters put in the socket (4096) the whole thing goes crazy. The procedure is called, but it is executed only up till the first "update" command. Then the readable-event of the socket triggers somehow again and the procedure is executed again (just untill it tries to read from the socket
and blocks there, because the socket is not yet filled at that time). I´ve tried to move the "update" command some lines forward. The result is the same - the first "update" met causes the read-event to trigger. If there are not 4096, but 4095 or 4097 characters read from the socket everything works OK.
Are there any "Voodoo numbers" in using sockets? :-]
Any ideas are appreciated
 
I'm not a socket specialist but two things:
- standard buffer length is 4096,
- fileevent matches with vwait (not update).
Sounds like update is a one shot trigger and vwait is a continuous trigger.

A good exemple of using sockets can be found at (How to send a file through a socket connection).

HTH

ulis
 
Thanks, ulis!
Look : normally "update" does not (and I think should not) cause triggering of the sockets. I've tested - by the length !=4096 none of the "update"'s cause the procedure to be called. Furthermore I used them here for graphics, not for sockets.
 
I think it all about this buffer standard length. I've tried to read 4096 * 2=8192 chars. The same effect : after update it triggers again and blocks. Can I cheat it? The first thing I thought of was just count the characters before they would put in the socket and add a " " at the end in case of $count%4096 = 0. But it is not very elegantly. Can the handler do it itself?
 
I don't know: I am at the very beginning with sockets.

Some thoughts:

Do you can use vwait?
vwait waits until the variable in argument is modified.
So you can:
- set all callbacks (with fileevent),
- enjoy receiving the data,
- set the vwait variable when the data are exhausted.

Can you sketch your app and post it?

Are you sure you need sockets? Maybe pipes would be a better solution.

Good luck

ulis
 
It's diffificult to figure out what might be going on from what little you've told us so far. If you could reduce the problem to a small code sample and post just that, we'd be happy to take a look at it and see if we can figure out what's going on. And as Cameron Laird has often said, in the process of reducing the code down to the very basics to demonstrate the problem to someone else, you often end up identifying the problem yourself.

Here's a few more thoughts based on what you've said so far...

Yes, 4096 bytes is a "magic number" with Tcl channels (and often with all applications, whether or not they're written in Tcl). By default, all output to a channel is buffered in memory; the data isn't actually written until the buffer is full or you do an explicit flush of the channel. In Tcl, most channels by default use "full" buffering, with a buffer size of 4096 bytes. So unless you've explicitly changed the buffering on the channel, nothing is actually getting sent through your socket until you've written at least 4096 bytes.

You can query and change a channel's characteristics with the fconfigure command. For example, executing:

Code:
fconfigure $fid -buffering

returns the current buffering setting: "none", "line", or "full". Executing:

Code:
fconfigure $fid -buffersize

returns the buffer size in bytes.

You can also change channel characteristics by supply new values to the options. For example:

[tt]fconfigure $fid -buffering line[/tt]

configures the channel for "line buffering", in which case Tcl automatically flushes the buffer whenever it receives a full line -- 0 or more characters followed by a newline (\n). If you're using puts to send text message through your socket, it's usually a good idea to configure the socket's channel for line buffering.

The other issue is that update command you mentioned. Even without seeing any of your code, I'm almost certain that it's the root of your trouble. It's easy for Tcl "old timers" to misuse update, let alone relative newcomers. It's always a bad idea to use the update command unless you can be certain what the effects are going to be. And it's always a bad idea to call update from with an event handler (i.e., a fileevent callback, an after callback, or a widget callback). As the update documentation says:

"This command is used to bring the application “up to date” by entering the event loop repeatedly until all pending events (including idle callbacks) have been processed." (Emphasis added)

So as you can see, update doesn't process only the GUI events, it also processes all outstanding fileevents, too. So if you call update from within a socket handler, you end up invoking a second-level event loop which could conceivably call your socket handler recursively. The Tcl'ers Wiki ( has a page called "Update considered harmful," which goes into this in more depth. Suffice it to say that you never want to call update from within an event handler.

If all you want is for your GUI to refresh after reading some data, there's really nothing you need to do. Once your socket's event handler finishes, your script automatically returns to the event loop, where any outstanding GUI events are handled automatically. So I suppose a key question is, "What are you really trying to accomplish with that update?" What problem did you observe that led you to put it in your code in the first place? Whatever it was, I'm sure we can come up with a solution that doesn't involve update -- or at least, not in the way you attempted to use it. - Ken Jones, President
Avia Training and Consulting
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax
 

- I use vwait for that socket. Using "update" I wanted to achive absolutely another things (refresh GUI´s).
- What I am really trying to accomplish with those updates is to make all graphical things be shown (in groups, perhaps. You know, when some entries with labels are inside of frames Tk needs some time before they are placed normally), and not twitch at the end, when the whole application is on the screen. Well, they are not really shown to the user, but for Tk. And at the end the application is drawn on the screen as a whole, without any movements of widgets.

- Powerful brainstorming ( :-] ) resulted in one more idea:
the process runs so that after placing the text in the socket, the socket is flushed. The sockets option "bu
ffering" is set to full. So the socket will be read after it becomes full. (-buffersize 4096).
Can it be that the "flush" command is placed into the waiting loop (like all commands) and then the socket is read first because it is full and then, when "flush" is called from the loop with "update", the socket is
tried to be read again?

I´m sorry, I cannot post a portion of the code - it´s quite difficult to reduce, but I´ve found an example of socket, that seems to have the same problem. (First it didn´t, so I 'helped' it... >:->). All that you need is to extract all the three files in one directory and then run. First Server then Client. In Client just press the "Send" button. It will send 4096 bytes to server. The server will freeze.

I have the files as a *.tar archived. The question is how can post it?
 
I don't know of any ways to post files to this forum. However, you can email them to me at ken@avia-training.com as an attachment, and I'll take a quick look.

I am still virtually certain that your use of update isn't necessary for the result you want, and is most likely the primary perpetrator of your problem. As pointed out earlier, calling update invokes a second-level event loop to process all outstanding events -- so any outstanding "readable" events on a channel will also get processed, like it or not. There is a less-evil cousin, update idletasks, that processes only any pending "idletasks," which includes most window refresh operations, that might help if you absolutely insist on using some sort of update operation inside of your fileevent handler. But I'm going to do my best to convince you that you don't want to do any updating in your handler. :)

If your goal is to have your entire window "drawn on the screen as a whole, without any movements of widgets," using update in any form does exactly the opposite of your goal. It forces Tcl to handle any pending events immediately. So, if you've made a few changes to widgets, calling update tells Tcl that you want to see those changes immediately.

In contrast, the default behavior of Tcl is to handle screen updates in an efficient, rational manner. If you've created some widgets and then pack or grid them -- or if you change the configuration of previously packed or gridded widgets -- those changes aren't immediately reflected on the screen. Instead, Tcl waits until is gets to the event loop to process all changes at once. This saves processing time, as Tcl doesn't have to try to lay out the display repeatedly after every single widget modification. And the visual effect to the user is a smoother window refresh.

If your actual goal is to read a certain amount of information from a socket before performing some screen operation, update still isn't the way to acheive that goal. Instead, your fileevent handler should be storing that information away somewhere and testing to see if you've read the desired amount of data. Once you have, then it should trigger the changes -- perhaps by executing some other procedure responsible for modifying the display. It's also possible to build some or even all of your display "off-screen," and then display it when you've got all the data you need to populate that display. You can create and configure widgets to your heart's content, but those widgets won't appear on the screen until/unless you use pack or grid to display them. You can even build an entire toplevel window "off-screen." Just withdraw it (using wm withdraw) to hide it, and then display it (using wm deiconify) when you're ready to show it.

I'm kinda grasping at straws here to come up with solutions, simply because I've still got too many unknowns as to what exactly you're doing. Getting a chance to see some code will help a lot in coming up with some concrete suggestions. And whatever the case, I'm sure the solution is a lot simpler than what you've been trying to do. It usually is in Tcl. :) - Ken Jones, President
Avia Training and Consulting
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top