After a long day of coding, I have come up with my last coding task of the day...
I'd like to have it so that a Winsock control receives data, looks at it, and based on what it gets does one of two things...
Lets say the program receives the letter "r" it will perform MsgBox "R"
Lets say if the program receives anything else, it will apply it to a text box, and then save it to a text file.
Program 1 Action: Sends Letter "R"
Program 2 Action: MsgBox "R"
Program 1 Action: Sends multilined contents of TextBox
Program 2 Action: Receives content and stores it as is (including lines) in a txt file...
Is this do-able? If so, how would I go about coding it? My brian is totally fried after a whole 14 hours of working on code!
Yes - I am familiar with the *basic* workings of the controls. I know how to start a connection, and how to spesify ports and IPs... That's pretty much it.
Now, as per my example, I'd like to have it so that if the received string says just "R" is should do something, but if it contains anything else, it should store it to the txt file... Would something like this work:
Code:
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
Winsock1.GetData string1
If string1 = "R" Then
MsgBox "R!"
Else
text1.text = text1.text & string1
' Then save the file?
End Sub
Yes, do not send data immediately following the connect. You have to wait until you are actually connected before you can send data. You are connected when your Winsock1_Connect event is fired.
That has never happened to me. What does the error message say?
But...
Not sure if you're still using string1 as an example but I'd use something a little less ambiguous like strData and I'd rename the winsock control - one of my pet hates is not renaming controls :P
Make sure you declare the variable.
Also be warned that just because you send one line doesn't mean it'll come out that way. For example, if you send three things quickly it can arrive as 1 string, or if you send one huge string it can arrive as 5 small strings.
If Winsock1.State = 6 Then
label4.Caption = "Connecting"
ElseIf Winsock1.State = 7 Then
label4.Caption = "Connected"
ElseIf Winsock1.State = 0 Then
label4.Caption = "Closed"
ElseIf Winsock1.State = 8 Then
label4.Caption = "Clossing"
'MsgBox "closing"
'wskSend.Close
ElseIf Winsock1.State = 9 Then
label4.Caption = "Error"
ElseIf Winsock1.State = 2 Then
label4.Caption = "Listening"
ElseIf Winsock1.State = 1 Then
label4.Caption = "Open"
ElseIf Winsock1.State = 7 Then
label4.Caption = "Connected"
End If
So when I get "Error" I simply get "Error".
You get "Error" because that is what you print, not what the actual error is. Use the Winsock1_Error event to trap your errors instead of the Winsock1.State = 9. In that event you will recieve the proper error number and a description of the error. Remember, do not attempt to send data until after your Winsock1_Connect event is entered. Then and only then are you sure you have connected to the other side.
By your description of the other system I get the impression it is not yours otherwise you would know what the other system is doing. Naturally if the other system closes the socket you will get an error if you attempt to send it data. On way to know if the other side has closed the socket is in your Winsock1_Close event. This event is entered whenever the otherside closes it's socket. Likewise, if you close your end first the other side's Winsock_Close event will be triggered.
Yeah, ditto, without seeing both server/client code I can't really help anymore. There is no logical reason that a connection would close by itself after receiving data.
Dim dataStr As String
Private Sub restartunit_Click()
dataStr = "Restart"
Winsock1.SendData dataStr
End Sub
Code:
Private Sub winsockconnection_Click()
Winsock1.Close
Winsock1.RemoteHost = remoteunit.Text
Winsock1.RemotePort = 15151
Winsock1.Connect
End Sub
Here is my remote code:
Code:
Private Sub Winsock1_ConnectionRequest(ByVal requestID As Long)
Winsock1.Close 'this resets our socket ready to accept the incoming connection
Winsock1.Accept requestID 'accept the connection!
MsgBox "Connected!"
End Sub
Code:
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
Dim strData As String
Winsock1.GetData strData
If strData = Restart Then
MsgBox "Restart"
' Restart NT
ElseIf strData = "DownloadConfig" Then
MsgBox "Download Config"
' Run the Config Download Timer
ElseIf strData = "Update" Then
MsgBox "Update"
' Run The Update Timer
Else
' Failed, sorry.
End If
End Sub
Code:
' In the Form_Load Event
Winsock1.Close
Winsock1.LocalPort = 15151
Winsock1.Listen
I can connect, and if I put a MsgBox in the remote system on connection it will pop up.. But I cant send any data, nothing it getting through to the other end... I think its my sending method on my local side?
Well, exactly at what point in time do you click on restartunit_Click?
I don't think you are paying attention to anything I have told you. You cannot send data until after your Winsock1_Connect event has been entered and yet I see no Winsock1_Connect in your code.
In your DataArrival you test for Restart and not "Restart" which will cause your code to pass to the Else clause which you do nothing.
The buttons to send data are disabled, unless Winsock is connected, if Winsock is connected the buttons are enabled... I have gotten it to work, simply because of what you said Restart, vs. "Restart".
Without, the Winsock1_Connect event I have been able to connect and send / receive data now. The only problem I still have is that I can connect once... Then if I disconnect, and try to reconnect again (without restarting the program) it wont connect. Do I need to add a Winsock Close event or something?
Yes, in the Close event you need to Close then winsock control, on both sides. I suggest you read this link (article links on left side). It contains great info on a bunch of winsock topics from beginner to intermediate.
It is better programming to have a _Connect sub and in that sub you enable the button(s) that do the sending of data. You will, of course, actually connect without you having that sub but then it is not always gauranteed whereas using the _Connect sub is a guarantee. It's up yo you how you program it I am only suggesting the better way.
When you disconnect both sides have to close their sockets. You know when one side has disconnected when your _Close sub is entered. In that sub you close your socket because the other side has already done so.
You should rely on these subs instead of testing the status of the socket but again that is up to you.
The server side, once closed must return to the Listen statement otherwise you will not be able to re-connect unless you restart the server application.
I want to point out that there are two ways to program the server. one way, like the way you did it, is to use the same socket for both listening and then use it for communications. Using this approach you will always have to return to the Listen statement after the socket has been closed. The other way is to use one socket for listening and one or more other sockets for actually making the connection request. This way the server's Listen socket remains open and the server is always in a Listen mode. In this approach you need not return to the Listen statement because the server is already doing it. You simply close the socket(s) you used for communications and not close the server's socket. Also in the approach you used you can only have one client at a time connecting to the server. Not good in the real sense of Client/Server applications.
Last edited by jmsrickland; Sep 10th, 2008 at 10:19 AM.
Then don't use the Form_Load to do the listening. Use another Sub for this. It is bad practice to use the Form_Load event to have your server socket listen. Not good programming technique to use a timer for what you are using it for.
NOTE:
You can lead a horse to water but you cant make him drink it
Last edited by jmsrickland; Sep 10th, 2008 at 10:31 AM.
How would you do it since my way is bad practice?! I'm new, gimme a break.
I have been telling you the correct way all along; you just haven't paid any attention to it.
First, I would use a socket array instead of a single socket. Socket(0) will be the socket that the server listens on. Socket(1) will be the socket that the server loads and uses as the connection request socket thus becoming the communication socket. When the client closes his socket you need only to close Socket(1) and Socket(0) remains in the Listen state therefore eliminating the need to return to the server socket at the Socket.Listen.
Second, if I was to use a single server socket I would put a call statement in the Form_Load event which calls the server socket listen sub. Then on client closing I would put another call in the server socket close event to call that same sub thereby elimating the need for a timer event (which, by the way, you are the first programmer I have ever seen in all my years of socket programming to use a timer to trigger the listening state). Like this:
Code:
'
'
Private Sub Form_Load()
'
' Do whatever needs to be done here
'
ServerListen
End Sub
Private Sub ServerListen()
Socket.Close
Socket.LocalPort = 15151
Socket.Listen
End Sub
Private Sub Socket_ConnectionRequest(ByVal requestID As Long)
'
' Do same thing as you are already doing
'
End Sub
Private Sub Socket_Close()
ServerListen
End Sub
'
'
'
'
Above is for a single server socket. Using two sockets eliminates the call to the ServerListen sub in the Socket_Close() event.
Also, you should always have a Socket_Error(.....) event to trap any unexpected error(s) that might occur.
The above is the correct way. Maybe not the very best since I have seen much better socket programming but for a simple application like yours the above is the way to go. Using a timer is pointless and your boss would probably make you re-write your code. If this is only for you and you alone then you can do it anyway that siutes your fancy but I am just trying to help you get it done right from the start.
Here is what I've been able to develop, using the code here, as well as the link that was provided. I will leave you with this one note though, I hope you aren't planning any malicious works with this. I only say this, because I know how easily it would be to modify a few lines of the code Ill post, and this code can become classified as trojan material. Admin: if you feel the need, remove my attachment.
wxmancanada, I don't normally do this, but if you do use some of my code, I'd like to see (via PM if nessacary) your full code. Just out of curiosity.
Code not 100% mine, as I basically copied and modified to suit my needs, but info was given on a free to use basis. Nor is it 100% free from errors. Code is not commented on, as it is fairly straight forward... exception being that the client relies on the server to update the clients screen (alowing for custom messages to be used, depending on the data entered, after server processing)
JmsRickland, could you show me how such an array would work? Would it be possible (or needed) to use a dynamic to support any number of connections?
Last edited by EntityReborn; Sep 10th, 2008 at 10:02 PM.
.....show me how such an array would work? Would it be possible (or needed) to use a dynamic to support any number of connections?
Using a single socket server (as in the OP's approach) allows for only one client to connect. Once the server has established a connection it is locked from acepting any other requests because the socket is no longer in the Listening state.
In order to get around this problem it becomes necessary for the server to have a way to do both listening (all the time) for incomming requests and also carry on a normal communications with one or more clients.
Answer. The server must use more than one socket. At the minimum, two sockets are required, one socket is used throughout the entire life of the server application and remains in a Listening state all the time. The other socket(s) will be used to carry out the communications between the server and one or more clients connected at the same time.
To make the server in it's simplest form is to put one Winsock control on the Form and give it an Index of 0 (zero). This is the base socket of the array and it will be used as the Listening socket. So, here's how it works....
Code:
Dim Clients As Integer
'
'
Private Sub Form_Load()
'
'
'
ServerListen
End Sub
Private Sub ServerListen()
Socket(0).Close
Socket(0).LocalPort = 15151
Socket(0).Listen
End Sub
Private Sub Socket_ConnectionRequest(Index As Integer, ByVal requestID As Long)
Clients = Clients + 1
Load Socket(Clients)
Socket(Clients).Close
Socket(Clients).Accept requestID
End Sub
Private Sub Socket_Close(Index As Integer)
Socket(Index).Close
End Sub
Private Sub Socket_DataArrival(Index As Integer, ByVal bytesTotal As Long)
Dim s As String
Socket(Index).GetData s
'
'
'
End Sub
I'm not trying to implement a full-blown featured server but only to show you the very basics of how to get a multi-client server application on the way. The above code is by no means meant to be complete in all that is necessary nor am I implying that other programming techniques would not be better that what I am showing. There are many many example of excellent multi-client chat programs around here and I do not need to extend on that since you can find all you need to know by searching on the key word multchat, multiclient, etc.