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 Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

2 Winsock questions.. 2

Status
Not open for further replies.

kodr

Programmer
Dec 4, 2003
368
I've searched every way I can think of, and I'm down to 2 questions...

I'm implementing a client/server application that needs to send small packets of data back and forth. I'm using TCP, and everything is working okay, except for the issue of sending data.

From what I can tell, when you use winsock.senddata, the data is actually going to a buffer somewhere in the windows world and is sent by the underlaying programs/process/whatever that drives windows TCP connections, and is not actually handled by your program. I'm cool with that.

What I'm doing is to gather all related data in one string, transmit it, and i'm done with it. The recieving side see's the data come in as a 'packet' and processes it fine.

What is the (or is there) default size for the senddata buffer? If I decide to send a large chunk of data to the recieving end, how large can it be before it gets broken down into seperate 'packets'?

The reason I ask that is my client app needs a prefix code telling it what type of message/action is occuring, and if a chunk of data gets split, I need to ensure the follow on chunk gets the prefix code also.

The second question is, if I have a large string, what is a simple way of telling how large it is, so I can compare it to the buffer size I have remaining?

Thanks in advanced.
 
Answered my own question...

Lenb(string) tells you the length, and with that I can do some testing to figure out what a good delimiting size is.
 
The network will almost always break packets up to suit it's own needs, so you must not rely on a packet being a certain size.

What you should do is one of two things:

1) Include a message length as one of the first things in the message you send (so you're reasonably assured of it arriving in the first packet). You can then read from the socket multiple times until you have that many bytes. Be sure to save any bytes after that amount, as it will be the start of the next message.

2) Embed a "signal" at the end of your message to indicate the end. This works great for XML, as you just look for </tagname> to know when you're at the end of one message. Same caution as above applies -- anything after this is the start of the next message.

The reason why you must do this is that TCP/IP is a stream-based protocol, and not a message-based protocol. So everything that gets sent is just a series of bytes, one after the other, with no special connotation applied to them. It's up to the application (ie. your code) to determine message boundaries (if any).

Even if you were to only send 100 bytes at a time -- there is a chance that some network segment somewhere will want a smaller packet size, and break it up into two packets in order to successfully transmit it. So don't rely on the size of the packet.

Chip H.


____________________________________________________________________
Donate to Katrina relief:
If you want to get the best response to a question, please read FAQ222-2244 first
 
Chip, thanks for the response. This will give me something to ponder over the long weekend.

I've put a lot of time into the current framework of my application, and I'm not looking forward to basically gutting what I've got and doing it the right way. I was working under the assumption that what I sent, arrived exactly as I wanted it to. I should know better then that..
 
Forget packets, you don't deal with packets in a case such as TCP over IP. Instead you deal with streams, which is the whole point of TCP.

I suspect when you are thinking of "packets" you mean "messages," and as I said, TCP doesn't provide such a thing. Worse yet, since you are dealing with async I/O and real-world buffering (unlike in the case of disk I/O of streams) you have responsibility for reassembling the stream as you need it.

You'll need to insert message framing of some sort yourself at the sending end, and at the receive end you need to reassemble the stream and then pull off messages as you recognize them in the stream. The sender's framing is what your receiver's recognizer works against.

Avoiding incorrect terminology like "packets" will save you a world of grief when working with Winsock.

Framing can be as simple as the form we've grown so used to with textfiles we hardly realize we use it: CrLfs between messages. From there the sky is the limit, though many people tend to use things like two to four bytes of "length" as a header. This permits your messages to contain any octet values you might need.
 
Thanks for the response. You're right, I'll avoid using packets. I knew it was wrong, just didn't have the terminology to state what I wanted to say.

I've got a basic message header I've started to use, a 3 digit message indicator, bracketed by special characters that will never appear in the message body.

Based on Chip's reply I'm looking into adding the message length immediatly behind the message indicator (i.e. #113*132#*blahblahblah...) Where #113* is the message type, and the length is 132, and #* indicates the start of the actual message, but I may use Chr$(0) instead, and use Split to break out individual parts of the message.

I guess sending the data is the easiest part, but the trick is at the receiving end...

What I'm imagining (and correct me if I'm wrong) is to receive using getdata and put the incoming message into a buffer, then kicking to a sub or function that breaks the data down. Basically if the data starts with a valid message indicator, look for a total lenght of x from the next part of the message, and process that message. If the length is less, then hold the message in a buffer while waiting for the rest of the message. Also need to handle what happens when a keep alive message comes in during the middle of a control message.

This leads me to the question, with a TCP connection, do I need to use a keep alive process to verify the connection still exists, or could I use a timer to periodically check the state of the winsock? Right now I'm using both, but it would simplify things to eliminate the keep alive messaging.

I thought I read somewhere that you could loose the connection (for various reasons) and the winsock state would still show connected (7) for a time.

When I get all of this done, I'd like to put together a winsock tutorial. I know there's alot of them out there, but they seem to just touch the basics of a small chat client/server app, and don't get into this detail.
 
Well one way to handle the received stream is to do much as you said: when data arrivals occur grab whatever is available and append it to an application-level buffer.

Personally I'd forego the gingerbread, and I'd put the length field at the head and make it fixed-length and self-inclusive (msg length includes the length field). You don't have to of course.

If you use a length field in your message frame header the resulting process can look something like:
Code:
'Global.
Buffer As String
:
{within data arrival event handler}
'Locals.
Fragment As String
MsgLen As Long
PartialMsg As Boolean
Const LenOffset = 1
Const LenLen = 4
Const LenMinimumHeader = LenOffset + LenLen - 1
  

GetData Fragment
Buffer = Buffer & Fragment
PartialMsg = False
Do Until PartialMsg Or Len(Buffer) < LenMinimumHeader
  MsgLen = CLng(Left$(Buffer, LenOffset, LenLen))
  PartialMsg = Len(Buffer) < MsgLen
  If Not PartialMsg Then
    ProcessMsg Mid$(Buffer, LenOffset + LenLen, MsgLen - LenLen)
    Buffer = Mid$(Buffer, MsgLen + 1)
  End If
Loop

Here I used a 4-digit msg length as the first header field. I don't care about your msg key field here, I let ProcessMsg() worry about splitting that off and interpreting it.

Note that it is important to wait until at least a minimal header has been accumulated in Buffer before trying to examine the msg length header field.

Watch out for tying things up too long in this subrountine processing incoming data. You could miss data arrival events.
 
I like that, thanks. This gives me a good place to start, what I had in mind was not that effecient.

I'm going to mess around with this over the next few day's. The project I'm working on is for work, but I'm thinking I can make a good framework for several projects out of this.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top