Link to home
Start Free TrialLog in
Avatar of imarshad
imarshadFlag for Pakistan

asked on

Winsock Help needed....... (Part 1)

Hi all,
         I am developing a system in which I will have a central server....... There will be some clients (at the maximum 10)..
These clients will connect to the Server and will get updated..... The updation is  simply the updation of a  text file that is present both at the Server and Client (Server will alway have the most updated text file).....I decided to use a Winsock Control for the Data Transfer and the Server-Client will communicate with the following sequence........

Server                                                                                       Client
                         
    <------------------------------Establish a Connection--------------------

    <----------------------------(Update Me)

                                        (Ready to Send File)------------------------->

   <----------------------------( I have x Lines/Bytes)                                   (So that only changes are transmitted)

                                        (Ok) ------------------------------------------>

                                       ("###") -------------------------------------->      (Tells to the client start of sending Data)

                                        (Data)---------------------------------------->      (Actual Data to be send)

                                      ("***") --------------------------------------->      (Tells the client End of sending Data)


  <------------------------------( I have Received x Lines/Bytes)


                                           (Ok) ---------------------------------------->

                  <---------------------------End Connection-------------------->


I have done some coding for this but I am stuck in some points.........So I want you people to help me out in this problem...
and let me tell u I am almost a novice as the Network Programming (Winsock Control ) is concerned


Connection Establishment......

I think that at the client side the connection establishment is very simple.......
Here is some of my code......

Private Sub Form_Load()

        WskClient.Connect "LocalHost", 1001
        If Err <> 0 Then
            WskClient.Close
        End If
WskClient.SendData "Msg_Update"

End Sub



Private Sub WskClient_DataArrival(ByVal bytesTotal As Long)
    Dim recBuffer As String
   
    WskClient.GetData recBuffer
    MsgBox recBuffer
        Select Case Left(recBuffer, 10)
    Case "Msg_RdySnd"  'Block Received
        xLines = CalculateNoOfLines()
        WskClient.SendData "Msg_xLines" & xLines
   
    Case "Msg_OKLine"
        xLines1 = Right(recBuffer, 10)
           
    Case "##########"
         StartOfFIle=True  

    Case "**********"
          EndOfFile=True
    Case "Msg_OkS"  'Ok you can begin to send file
        ReceiveFile( )
    Case Else
       
    End Select
End Sub

But the problem is at the Server SIde.......
Here is my code at the server side.....

Private Sub Form_Load()
    WskServer(0).Protocol = sckTCPProtocol
    WskServer(0).LocalPort = 1001
    WskServer(0).Listen
    intMax = 0
   
End Sub


Private Sub WskServer_ConnectionRequest(Index As Integer, ByVal requestID As Long)
    If Index = 0 Then
        intMax = intMax + 1
       
        Load WskServer(intMax)
        WskServer(intMax).Accept requestID
    End If
    lblInfo.Caption = "Connection Estabilished..."
End Sub

Private Sub WskServer_DataArrival(Index As Integer, ByVal bytesTotal As Long)
    Dim RecBuffer As String
    Dim j As Integer
    On Error GoTo GLocal
   
    WskServer(Index).GetData RecBuffer
    Select Case Left(RecBuffer, 10)
        Case "Msg_UPdate"
       
                WskServer(Index).SendData "Msg_RdySend"
               
        Case "Msg_xLines"
                NoOfLinesClient = Right(RecBuffer, 10)
                WskServer(Index).SendData "Msg_OKLine" & NoOfLines
                'xLines = LinesToSend(NoOfLines)
                WskServer(Index).SendData "##########"
                Call SendFile(NoOfLinesClient)
                WskServer(Index).SendData "**********"
        Case "Msg_RcvLin"
                RecLines = Right(RecBuffer, 10)
                'If not received all lines then send again
                WskServer(Index).SendData "Msg_OK_Snd"
        Case "Msg_Thanks"
                WskServer(Index).Close
        Case Else
       
        End Select
    Exit Sub
GLocal:
    MsgBox Err.Description
    Unload Me
   
End Sub


This code is almost the same as the one in MSDN......

Problem 1::

Since I donot know much about Winsock so here are a few questions that are stuck into my mind......

1) As the code illustrates that WskServer(0) is always in listening mode and whenever a new Request arrives it simply creates a new instance of of WskServer which accepts the connection.......So if my Server is running 24hrs/ 7 days then intMax=intMax+1 will cause the intMax value to be out of bounds of Long within a couple of Weeks.....How to avoid that?

2) Since I will have fixed no. of Clients that can communicate with my Server say only 3 then do I need to use it in this way that I have shown in the example?
How can I use it like this "if Client1 connects with me then Load WskServer(1) similarly for Client2 load WskServer (2) and when it disConnects UnLoad its respective Control i.e like Unload WskServer(1)  after Client 1 is being updated completely.....

3) How do the Server knows that Client1 is still connected with me  ?

4) How do the Client1 knows that it is still connected with the Server ?


Note:::::

This is the first Part of this series of Questions almost all of which will be focussing around Winsock.......

Imran Arshad
Avatar of imarshad
imarshad
Flag of Pakistan image

ASKER

Please do tell me some suggestions to improve my code or even better way of connecting and handshaking (Sort of)  in comparison to what I am doing right now.......
Avatar of anv
anv

visit the following link
of VBIP

they provide lot of help on using winsock control

http://www.vbip.com

also
following link
http://www.winsockvb.com

u'll get ur solutions on these two links...

u'll have to do some reading get the solution
SOLUTION
Avatar of anv
anv

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks anv and darkoLord for your help......This site contains really good articles even for a novice like me....

Idle_Mind,
                Thanks for your help and source code......I have almost got the idea.....Here is what I have got from your Code Please correct me where I am wrong.....

1) WinSock(0) at the server side is always listening and its purpose is only to Listen the Connection Requests from Clietns....

2) WinSock(1) will always be connected to the first Client that is trying to connect....and so on for the remaining Clients....

3) inputBuffer(index) will contain all the Commands/Data that is received from the Client

4) All commands will contain chr(1) as an indication that the command is finished.....and if I am sending multiple commands in one command then it will be separated by chr(0)

So now I have a few questions.....

a) If I want to know which Client is trying to connect to the Server how can I know ?
i.e. if I want to know who is connected onto the server on the socket WinSock(1) ?
Do I need to send some parameters from Client like this
msg = "UpdateInfo" & "Client A" & Chr(0) & numLines & Chr(0) & numBytes & Chr(1)
Winsock_ClientA.SendData msg

so that the Server will know this is "Client A"  or is there some direct method of finding who is connected on WinSock(1) ?

b) What I want to achieve is a sequential flow of my program......i.e After connection my Client will send some Command (Message), the Server will (when received that command) follow up with a command to the client and so on.....Like I have shown in my question....

Now as you have said that my Command might be divided into many parts and I might recieve "This is a Message" as "This is a Mess" and "age".....As long as the sequence remains tha same I have no problem as the  inputBuffer(index) will contain the complete command "This is a Message" which I can recognise ,decode and acknowledge.....But what happens if I get it in wrong order Like "ageThis is a Mess" How to handle such situations ? Are such situations Possible at all ?

So according to my algo the Server should not acknowledge Client that it has received some Command/Request/Message from Client but in fact it has received......How to tackle this situation as the client will be waiting for a response to the Command it has send?

Once these Queries are answered I will post  "Part 2"  of this question that will be rotating around Sending Large Text on WinSock.......

imran Arshad
>>I will post  "Part 2"  of this question

Of course as a new Question.....
a) If clients have static IPs you can use .RemoteHostIP property to get it's IP... otherwise you would have to send some "authentication" data first
b) Received data cannot be messed up, however you could receive multiple commands in one... thats why you should end each command with a nullchar (vbNullChar constand) as you can see in Idle_Mind's example above...

As for sending response that the command has been received, you don't need to do this... My advice is to split your communication to multiple stages and then you can use winsock's .Tag property to know which stage is each client in...

Also it is easy to mark each data with a number... for example: "hello" can be 1, "ok" can be 2 and so on.... you can then use Chr$(Command_ID) so it takes only one byte and you can parse it easily...

Darko
>>As for sending response that the command has been received, you don't need to do this... My advice is to split your >>communication to multiple stages and then you can use winsock's .Tag property to know which stage is each client in...

Sorry I could not understand this concept.....What I am trying to do is to send some Command from Client and Trigger the next Event (Maybe send next command or send data or close connection)  in the Client only after the response from the first command has reached from the Server....Can you supply some source code for what you have suggested ?

>>If clients have static IPs you can use .RemoteHostIP property to get it's IP... otherwise you would have to send >>some "authentication" data first

So the method that I have suggested is good enough to work if I donot have Static IP?
msg = "UpdateInfo" & "Client A" & Chr(0) & numLines & Chr(0) & numBytes & Chr(1)
Winsock_ClientA.SendData msg
I wonder how "Huge Servers" like Kazaa and MSN Messenger work ? Since all of its clients donot have static IP.....Do my Messenger send my Information in the form of above example or do they also send my Dynamic IP  with my User Name ?
As far as I know one can check the IP address of whom one is chatting in MSN Messenger......


Imran Arshad

Well the source is very easy so it should only take a minute for you to write it... here's the concept:

Client:    Send command ----> server
Client:    Set .Tag property to "stage1"
Server:   Send response ----> client
Client:    checks which stage is now and then:
              Send command2 ----> server
              Set .Tag property to "stage2"
and so on...
so basically client always knows which response is it waiting for :)

However, are you ABSOLUTELY sure you really need to wait for response??


Easiest way of managin "Huge Servers" is to create a class for each user that contains his userinfo... some of the servers work with user hashes, others with IDs, etc...

Darko
1) WinSock(0) at the server side is always listening and its purpose is only to Listen the Connection Requests from Clietns....

Correct.  (Some people use a completely different Winsock control to always listen)

2) WinSock(1) will always be connected to the first Client that is trying to connect....and so on for the remaining Clients....

Initially the clients will be connected to the same Index number as the order that they connected in.  After people disconnect, the winsock control they were using is closed, BUT NOT unloaded.  Subsequent connections can then serviced using those already loaded winsock controls.  For instance, if you have three clients connect then they would serviced like this:

    Index 1 --> Client #1
    Index 2 --> Client #2
    Index 3 --> Client #3

Then if Client #2 disconnects it will look like this:

    Index 1 --> Client #1
    Index 2 --> sckClosed
    Index 3 --> Client #3

Now when the next client connects they will be serviced using Index 2 since it is available and no new winsock is loaded at this time:

    Index 1 --> Client #1
    Index 2 --> Client #4
    Index 3 --> Client #3

Now if Client #1 and Client #4 disconnect you will have this:

    Index 1 --> sckClosed
    Index 2 --> sckClosed
    Index 3 --> Client #3

Index 1 and Index 2 will not be unloaded because there is still a client connected above them.  Unloading them would leave a literal hole in the index array that makes the code nasty since you have to check if the index is instatiated before using it.  This requires Error trapping and makes the code harder to read.  Once Client #3 disconnects, Index 1, Index 2 and Index 3 will all be unloaded leaving only Index 0 listening for connections.

3) inputBuffer(index) will contain all the Commands/Data that is received from the Client

Correct.  DarkoLord suggests using the .Tag property to store each clients stream buffer.  Either way will work fine since they are both persistent and not local to the DataArrival() event.

4) All commands will contain chr(1) as an indication that the command is finished.....and if I am sending multiple commands in one command then it will be separated by chr(0)

Yes and no.  The way I had coded it, a message is ended with Chr(1).  The purpose of Chr(0) was to delimit values for the SAME command so you could easily send related pieces of data like header information for the size of you file.  With my code you wouldn't send more than one command seperated by Chr(0), only Chr(1).   This is just the way I chose to do it.  You need to decide on a protocol that works for your situation and pick delimiters that make sense.  In a plain text chat application, Chr(1) and Chr(0) work great.   If you are sending binary data, the don't work so great since those characters may actually exist in the stream.  In that case you could use longer delimiters that are unlikely to occur in the stream.

a) If I want to know which Client is trying to connect to the Server how can I know ?

As Darko said, unless your clients have Static IPs then they will have to "login" once they connect.  This requires a small bit of setup on the client side unless you can install each one with some kind of unique identifier in a data file to use as a login ID.  You would just make your own protocol for the login message like (if you have passwords):

    msg = "Login" & Chr(0) & "Client A" & Chr(0) & Password & Chr(1)
    Winsock_ClientA.SendData msg

b) What I want to achieve is a sequential flow of my program

You wont get the packets out of order using the TCP protocol.  That is possible using the UDP protocol however, which is why you don't see it used very often for file transfers since you have to manage the packets very carefully at a low level and possibly store them until you receive missing packets to fill in the holes.

Regards,

Idle_Mind
>>However, are you ABSOLUTELY sure you really need to wait for response??

Yes because some of these might contain data that is going to be used in the subsequent commands.....Like the NoOfBytes or NoOfLines parameter that will tell me what chunk of File I need to send(the unupdated part of file).....

I will come back in about 90 min. and then I will try to Close this question and post the New Question....

Imran Arshad
>>You wont get the packets out of order using the TCP protocol.
>>The TCP protocol simply states that the information you send will arrive in the order you sent it, but not neccessarily in
>> the chunk size you sent it.

I had missed it in your earlier post......SO this is good news for me.....

Also what will happen if  both server and Client are connected but one of them gets disconnected from the internet while protocol \ command interchange is still in progress??
Will the ServerWinsock_Close( ) and ClientWinsock_Close( ) event be fired at both ends ? Since I am currently developing both the Server and Client on the same system I don't know how will it react on the internet.....

I think that whenever a connection is closed then I need to flush inputBuffer(index) for that index that has been closed...
I donot know what this command is doing

ReDim Preserve inputBuffer(Winsock1.UBound)

But lets say I have this situation

    Index 1 --> Client #1
    Index 2 --> Client #2
    Index 3 --> Client #3

and then Client # 3 gets disconnected

and  a new Client # 4 comes then the following will be the situation

    Index 1 --> Client #1
    Index 2 --> Client #2
    Index 3 --> Client #4

and the inputBuffer(3) will contain the previous data as well as the newer data........Isn't it like this?

Also what will be the safest way to close the connection...... i.e. the client has received the file....Do I need to close the connection from the Client Side or the Server side ? and Is this line enough at the client side ?
WinsockClient.close

Imran Arshad

>> what will happen if  both server and Client are connected but one of them gets disconnected from the internet while protocol \ command interchange is still in progress??
Will the ServerWinsock_Close( ) and ClientWinsock_Close( ) event be fired at both ends ?

I believe you will get an Error event from the winsock control notifying you, but I'm not actually sure as it is hard to create those conditions when both the server and client are being tested on the same machine.  One thing you can do is always check the state of the connection before attempting to send anything:

    If Winsock1(0).State = sckConnected Then
        Winsock1(0).SendData "some data..."
    End If

>> I need to flush inputBuffer(index) for that index that has been closed...

I am clearing the input buffer when the connection is accepted in ConnectionRequest():

    ' Load a channel if none available
    If acceptIndex = -1 Then
        acceptIndex = Winsock1.Count
        Load Winsock1(acceptIndex)
        ReDim Preserve inputBuffer(acceptIndex)
    Else
        inputBuffer(acceptIndex) = ""
    End If

If acceptIndex = -1 then we have to load up a new winsock control to handle the new connection.  If this is the case then we also have to increase the size of the input buffer array to match the size of the winsock control array.  This is what the

    ReDim Preserve inputBuffer(acceptIndex)

line does.  It makes the inputBuffer array the same size as the winsock control array.  The Preserve word keeps the existing data in the array so it doesn't get lost.

>> Do I need to close the connection from the Client Side or the Server side ?

It doesn't matter but personally I would make the client side initiate the disconnect so that the close event will fire at the server side and make it clean up the winsock control array.

>> and Is this line enough at the client side ?
WinsockClient.close

Yes.

Regards,

Idle_Mind
Thanks Idle_Mind for your help and I will love to see you participate in the other Question as well as I have gained quite a few things while discussing with you......

Imran Arshad