[RESOLVED] A question in Winsock
This is my problem.
I have a server and many clients are connected to each other "thru" the server.
Now If client-1 wants to send a file to client-2 then both of them should be
connected directly using another winsock.
How can I achieve this ? (Bcoz client-1 does not know the ip of client-2).
Re: A question in Winsock
There should be a means of resolving IP adresses, e.g. usernames can be checked at server to retrieve corresponding IP address.
Re: A question in Winsock
How can i get the External Ip address.
If I use the RemoteHost property i recieve only their network ip address.
Re: A question in Winsock
This is why you need to develop a protocol for your program. AKA: a list of commands prefixed with a number so the program knows what kind of data is being sent. I don't do it quite this way anymore, but here is an example.
You can use any numbers you like, and don't even have to use numbers at all, but it's just an example:
Client (to server):
Code:
Message: 100 Nickname MessageText
Private Message: 200 Nickname Recipient MessageText
Server (to client(s)):
Code:
Message (relay to all clients): 100 Nickname MessageText
Private Message:
To recipient: 200 Sender Message
To sender:
User not online: 201 Recipient (note: 201 for error and not 200)
Sent: 200 Recipient Message
That is a very basic example of a very basic protocol. To do what you're asking, you should store the IP address of every connected client (or use Winsock(Index).RemoteHostIP on the server), along with their nickname.
Then you could update the protocol with something like:
Client (to server):
Code:
File transfer request: 300 Recipient FileName Size
File transfer response:
Accepted: 301 Sender FileName Size
Denied: 302 Sender FileName Size
Server (to client(s)):
Code:
File transfer request:
To recipient: 300 Sender FileName Size
File transfer response:
To sender:
Accepted: 301 Sender FileName Size IPAddress
Denied: 302 Sender FileName Size
I always write out a simple protocol.txt file like the above before even beginning on the VB code. Then the framework for your client/server project is done and already thought out and it's just a matter of writing the code for it.
Re: A question in Winsock
I do have my own protocol.
But that's nothing to do with my question.
Re: A question in Winsock
Yes it has. Clients ask the server for details regarding other clients in order to resolve IP addresses... implied is the protocol DigiRev mentioned.
Re: A question in Winsock
But even the server does not know the "external" ip address of other clients.
Re: A question in Winsock
I wasn't sure if you were already using a protocol or not, I guess I assumed you weren't...but I was mostly saying just request the IP of the other user from the server...
You should store info on the server for each client in something like a UDT array, and re-dimension that array as new clients connect (the same as you are doing with the Buffer string for each client in your "BlueChat project").
Ex:
Code:
'In your module (Module1.bas)
Public Type CLIENT
strNickname As String
strIPAddress As String
End Type
Public udtClients() As Client
Public Function UBClients() As Integer
On Error GoTo ErrorHandler
UBClients = CInt(UBound(udtClients))
Exit Function
ErrorHandler:
UBClients = -1
Exit Function
End Function
Then modify your Winsock_ConnectionRequest() event.
Code:
Private Sub Winsock1_ConnectionRequest(Index As Integer, ByVal requestID As Long)
'
'The winsock(0) is the control that is only listening and only accepts
'the connections.
'
'Check if the Index is 0
'Empty client
Dim udtEmpty As CLIENT
If Index = 0 Then
'check all the existing winsock's state
'If closed then accept the connection in this itself and flush its buffer.
For i = 1 To ind
If Winsock1(i).State = sckClosed Then
Winsock1(i).Accept requestID
Buffer(i) = ""
'Reset client info.
udtClients(i) = udtEmpty
'Store their IP address.
udtClients(i).strIPAddress = Winsock1(i).RemoteHostIP
Exit Sub
End If
Next
'Did not find any winsock that is closed. so increment the ind by 1.
ind = ind + 1
'Load the Winsock
Load Winsock1(ind)
'Create a new buffer for the new winsock with the same index number.
ReDim Preserve Buffer(ind)
'Create new user array item.
ReDim Preserve udtClients(ind) As CLIENT
'Accept the connection.
Winsock1(ind).Accept requestID
udtClients(ind).strIPAddress = Winsock1(ind).RemoteHostIP
End If
End Sub
Now you can access a user's information using the Index of the Winsock control, ex: udtClients(Index).strNickname
Then you would set their nickname when they login. I haven't looked at your code much so this might be off, but it would probably go in the DataArrival() event:
Code:
Private Sub Winsock1_DataArrival(Index As Integer, ByVal bytesTotal As Long)
Dim Record As String 'Net data recieved
Dim EORPos As Long 'Pos of eod mark
Dim Finished As Boolean '..finished processing or not?
'Get the message in a str Variable.
Winsock1(Index).GetData message
'Append the data to the particular client's buffer.
Buffer(Index) = Buffer(Index) & message
Do
'Check wheather the buffer contains the eod mark
EORPos = InStr(Buffer(Index), eod)
'If so then...
If EORPos > 0 Then
'remove the eod mark and store it in the record.
Record = Mid(Buffer(Index), 1, EORPos - 1)
'******PROCESSING PART*******'
If datapassthru(Record) = 0 Then
auth = authenticate(Record)
If auth = False Then
Winsock1(Index).SendData "***|\/|***P" & "0 " & "Invalid Username/Password. Connection Forbidden!" & eod
Else
Winsock1(Index).SendData "***|\/|***P" & "1 " & "Connected to " & Winsock1(0).LocalIP & eod
'// MODIFICATION //
'Set user's nickname?
Dim strU As String
strU = getuser(Record)
udtClients(Index).strNickname = strU
'// EOF MODIFICATION //
End If
ElseIf datapassthru(Record) = 1 Then
If checkC(Record) = True Then
Winsock1(Index).SendData "***|\/|***C" & "0" & eod
Else
Winsock1(Index).SendData "***|\/|***C" & "1" & eod
End If
ElseIf datapassthru(Record) = 2 Then
CreateNew Record
Winsock1(Index).SendData "***|\/|***N" & "Your ID has been succesfully registered in the Bluehat server." & vbCrLf & _
"You can now login with your username and password." & eod
ElseIf Record = "*.*" Then
Winsock1(Index).Close
Else
For i = 1 To ind
If Winsock1(i).State = sckConnected Then
Winsock1(i).SendData Record & eod
End If
Next
End If
'********END OF PROCESSING PART*******'
'Check wheather if there is any remaining data
If EORPos + Len(eod) < Len(Buffer(Index)) Then
'then move it to the front of the buffer and loop again.
Buffer(Index) = Mid(Buffer(Index), EORPos + Len(eod))
Else '..no remaining data.
'then flush the buffer and exit the loop.
Buffer(Index) = ""
Finished = True
End If
Else 'You did not find any eor mark
'Exit the loop and wait for the remaining data.
Finished = True
End If
Loop Until Finished = True 'End loop when finished = true
End Sub
Now you can access a user's nickname and IP address using the Index argument of a Winsock event.
Then you would use the irrelevant code that had nothing to do with your question to request the IP address of another user.
Re: A question in Winsock
Quote:
Originally Posted by VIGGY808
But even the server does not know the "external" ip address of other clients.
Then how do you think direct connections are established in IRC and other chat networks? The server handles it all... in its rudimentary form server keeps track of unique username to IP mapping.
Re: A question in Winsock
Thanks DigiRev and leinad91.