I have developed an application for my game server. Now, in this application when I press "Connect" it sends data to my Game Server. And it does, but, the problem is, when it sends the connection it automatically closes it, and I don't want to close it because I have a socket plugin that kills the TCP connection after player leaves the game. Now on my localhost it works, the TCP doesn't "die" but on my vps it disconnects, can someone please check my code and see if I'm doing something wrong?
Dim p() As Process
Dim gta() As Process
p = Process.GetProcessesByName("samp")
gta = Process.GetProcessesByName("gta_sa")
If p.Count > 0 Then
MsgBox("Vec imate pokrenut SAMP - ugasite ga.")
ElseIf gta.Count > 0 Then
MsgBox("Vec imate pokrenut GTA San Andreas - ugasite ga.")
Else
Try
Dim prozess As Process = Process.GetProcessesByName("samp")(0)
prozess.Kill()
Catch ex As Exception
End Try
My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Software\SAMP", "PlayerName", TextBox1.Text)
Process.Start("samp://164.132.229.172:7777")
Dim client As New TcpClient()
client.Connect("164.132.229.172", 7775)
Dim sendBytes As [Byte]() = System.Text.Encoding.ASCII.GetBytes(TextBox1.Text)
Dim stream As NetworkStream = client.GetStream()
stream.Write(sendBytes, 0, sendBytes.Length)
Timer1.Start()
End If
End If
Timer:
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Dim pd() As Process
pd = Process.GetProcessesByName("Aimbot By The2Gamers")
If pd.Count > 0 Then
Dim InternetExplorer() As Process = Process.GetProcessesByName("Aimbot By The2Gamers")
For Each Process As Process In InternetExplorer
Process.Kill()
Next
End If
End Sub
Now this part down here is only server log from my vps:
[01:12:15] [LAUNCHER] Connection to Socket Server. | ClientID: [0] |
ClientIP: [92.241.153.29] [01:12:15] Remote client [0] has sent:
Joan_Mackey [01:12:16] [LAUNCHER] Player Socket disconnected|
ClientID: [0] | PlayerID: [0]
You should move the Dim client As New TcpClient() initialization to class level. Class level means that you put it outside any method (that is, outside any Sub or Function).
As it stands, your TcpClient is collected by the Garbage Collector after you've exited whatever method you put it in. After you've passed End Sub the TcpClient is technically no longer used, because you cannot access that specific instance anymore. The Garbage Collector checks for this when it runs, and as your variable is no longer used it will be collected.
When the Garbage Collector collects an object it starts releasing the object's unused resources. If the object (or any child object) implements the IDisposable interface, the Garbage Collector will first call that object's Dispose() method.
TcpClients are built on top of the System.Net.Sockets.Socket class. The Socket class implements IDisposable which means it has got a Dispose() method. The Garbage Collector will call this method for the underlying socket of your TcpClient. When it is called, the socket will automatically shut itself down and tell the endpoint that it's disconnecting - and this is what you are experiencing.
So to summarize:
The TcpClient is no longer used after you pass End Sub.
When the Garbage Collector runs it will start releasing the TcpClient's resources, and call Dispose() on the underlying socket.
The underlying socket will then tell the endpoint that it's disconnecting, and then it will terminate the connection.
Now your connection to the server isn't open anymore.
Related
I'm trying to build a simple Windows Forms app in VB.net (.net Framework 2.0 in order to support Windows XP) which allows multiple client PCs to send short text strings as UDP messages to a listening "server".
The "server" part must listen asynchronously and display the received text from each client as it arrives.
My code can't use the newer ReceiveAsync() function because it must support XP and thus must be built on .net Framework 2.0, which doesn't support these Async functions, so I'm using the BeginReceive() function and passing a callback.
It works perfectly for the first incoming UDP message, but the problem is that no additional messages are received. Even if I send the same message twice, nothing is output after receiving the first incoming message. It's as if the listener ignores anything after the first message, or as if it's hung in an incorrect state. Is there some sort of "reset" procedure that must be performed on the UDP listener after each incoming message in order that it will listen for further incoming data? (Note: no exceptions are raised)
Here's my listener code:
Private Sub btnListen_Click(sender As Object, e As EventArgs) Handles btnListen.Click
Dim state As New UdpState
listener = New UdpClient(CInt(txtListenPort.Text)) ' Create UDP client on specified port (all interfaces)
'Async receive data:
Dim ip As System.Net.IPAddress = System.Net.Dns.GetHostEntry("localhost").AddressList(0)
state.udpClient = listener
state.ipEndPoint = New Net.IPEndPoint(ip, CInt(txtListenPort.Text))
Dim callback As AsyncCallback
callback = AddressOf rx
listener.BeginReceive(callback, state)
lblListenStatus.Text = "Listening..."
End Sub
Shared Sub rx(result As IAsyncResult)
Dim r As UdpState = result.AsyncState
Dim endpt As System.Net.IPEndPoint = r.ipEndPoint
Dim client As UdpClient = r.udpClient
Dim bytes() As Byte
bytes = client.EndReceive(result, endpt)
Dim s As String = System.Text.Encoding.ASCII.GetString(bytes)
Debug.Print("Received string = " & s)
End Sub
Private Class UdpState
Public ipEndPoint As System.Net.IPEndPoint
Public udpClient As System.Net.Sockets.UdpClient
End Class
And here's the code I'm using to send data to this socket endpoint:
Private Sub btnSend_Click(sender As Object, e As EventArgs) Handles btnSend.Click
Dim send As New UdpClient
Dim s As String = txtSendMessage.Text
Dim b_len As Integer = System.Text.Encoding.ASCII.GetByteCount(s)
Dim b() As Byte
ReDim b(b_len)
b = System.Text.Encoding.ASCII.GetBytes(s) 'Convert text to bytes.
send.Send(b, b_len, txtSendIP.Text, CInt(txtSendPort.Text)) 'Blocking SEND.
send.Close()
End Sub
Note that I'm testing sending from localhost to itself - not even sending over the network.
Thanks for any insight.
I'm having an issue establishing a connection to my TcpClient using the local server address of 127.0.0.1 and port 1000. It attempts to establish a connection and then hits my Catch SocketException that it is unable to find a server.
I've set breakpoints and have went through the code line by line and it catches my exception once the line NetStream = Client.GetStream() is called from within my Try/Catch after pressing my button btnStart. Showing that no connection is being established at all. Why is this?
Public Class frmForm1
Dim Client As TcpClient
Dim connection As Socket
Dim NetStream As NetworkStream
Private Sub btnStartClient_Click(sender As Object, e As EventArgs) Handles btnStartClient.Click
Try
txtLog.Text &= "Attempting to connect"
Client = New TcpClient()
Client.Connect(txtAddress.Text, CInt(txtPort.Text))
NetStream = Client.GetStream()
' Catch errors in trying to connect to server
Catch SocketEx As SocketException
txtLog.Text &= "Cannot find server"
End Try
End Sub
It shouldn't be throwing my exception and then creating my NetworkStream Reader/Writer objects and print that they were created. As well as setting up the listening thread. However, I cannot even get that far as my Catch SocketException is called at the line NetStream = Client.GetStream()
You need at least 2 threads. One for the server to listen and one for the clinet to connect. Make sure to call .Start() on the TcpListener object (Server.Start() in your case) before trying to connect the client to the server.
I've written a Windows-based TCP server program based on some VB code I found on the internet several years ago (I can't find the link now, but it was called "multi-client server program" or something like that).
The server communicates with a couple of Enterprise iPhone client apps that I have also developed. I've successfully incorporated this code into two separate server programs that work just fine on both the development server and the production server. I'm working on a third iOS client application and a corresponding server program, which works fine on the development machine, but will not work on the production server -- the same machine that hosts the other two server programs with no problem.
It was working for a while, but as I have added more functionality to the server class, it seems to have stopped processing the incoming data, but only on the production machine.
The code that performs the connection functions is contained in a separate public class which is supposed to communicate with the Windows form that processes the incoming data. Using msgbox's for debugging tools, I have been able to confirm that the Client Connection class is connecting and is receiving the data, but it for some reason will not communicate that data with the Windows form.
My only thought is that it must be a threading issue, but I am not sure, and I have no idea how to find out.
To recap, just to be clear:
The code works fine on the development server, but not on the production server.
The client connection class is identical in every way with the other two working server programs.
That the client is communicating with the client connection class has been confirmed. The incoming data can be captured inside the connection class and displayed in msgbox's, so the data is getting through.
The Windows class that processes the incoming data is not receiving the data from the public client connection class.
EDIT: I should have included this in the original post: The development server is Win 7; the production sever is Windows Server 2012.
Because of the complexity of this code, I am not sure what snippets would be applicable for this, but I'll do my best to include what makes most sense to me here.
This is the entirety of the client connection class with the exception of the method that sends outgoing data. Again, this was copied from a website several years ago, and the comments are those of the original developer:
Imports System.IO
Imports System.Net.Sockets
Imports System.Data.SqlClient
Public Class ConnectedClient
Private cli As TcpClient 'declare a tcp client which will be the client that we assign to an instance of this class
Private uniqueid As String 'this will be used for the name property
Dim strErrorLogPath As String
Public Property name ''This will be the name of the ID containing its Unique ID
Get
Return uniqueid 'when we want to get it, it will return the Unique ID
End Get
Set(ByVal value)
uniqueid = value 'Used for setting the name
End Set
End Property
Sub New(ByVal client As TcpClient)
Dim r As New Random 'create a new random to serve as way to create our unique ID
Dim x As String = String.Empty 'declare a new variable to hold the ID
For i = 0 To 7 'we are going to have an ID of 7 randomly generated characters
x &= Chr(r.Next(65, 89)) 'create a generate dnumber between 65 and 89 and get the letter that has the same ascii value (A-Z)
' and add it onto the ID string
Next
Me.name = client.Client.RemoteEndPoint.ToString().Remove(client.Client.RemoteEndPoint.ToString().LastIndexOf(":")) & " - " & x 'set the name to the Unique ID
cli = client 'assign the client specified to the TCP client variable to we can operate with it
cli.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf read, Nothing) 'start reading using the read subroutine
End Sub
Public Event gotmessage(ByVal message As String, ByVal client As ConnectedClient) 'this is raised when we get a message from the client
Public Event disconnected(ByVal client As ConnectedClient) 'this is raised when the client disconnects
Sub read(ByVal ar As IAsyncResult) 'this will process all messages being received
'bn-note: This is the entry point of the data being received from the client.
Try
Dim sr As New StreamReader(cli.GetStream) 'initialize a new streamreader which will read from the client's stream
Dim msg As String = sr.ReadLine() 'create a new variable which will be used to hold the message being read
If msg = "" Then
RaiseEvent disconnected(Me) 'WE CAN ASSUME THE CLIENT HAS DISCONNECTED
Exit Try
'msg = "Null Message"
End If
WriteToRawIncomingDataLog(msg)
RaiseEvent gotmessage(msg, Me) 'tell the server a message has been received. Me is passed as an argument which represents
' the current client which it has received the message from to perform any client specific
' tasks if needed
cli.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf read, Nothing) 'continue reading from the stream
'End Ifz
'Catch ex As System.NullReferenceException
Catch ex As Exception
Try 'if an error occurs in the reading purpose, we will try to read again to see if we still can read
Dim sr As New StreamReader(cli.GetStream) 'initialize a new streamreader which will read from the client's stream
Dim msg As String = sr.ReadLine() 'create a new variable which will be used to hold the message being read
WriteToRawIncomingDataLog(msg)
RaiseEvent gotmessage(msg, Me) 'tell the server a message has been received. Me is passed as an argument which represents
' the current client which it has received the message from to perform any client specific
' tasks if needed
cli.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf read, Nothing) 'continue reading from the stream
'End If
'Catch ex2 As System.NullReferenceException
' Stop
Catch ' IF WE STILL CANNOT READ
RaiseEvent disconnected(Me) 'WE CAN ASSUME THE CLIENT HAS DISCONNECTED
End Try
End Try
End Sub
Here is the Windows form code that processes the incoming data:
Private Sub formMain_Load(sender As Object, e As System.EventArgs) Handles Me.Load
Try
Dim listener As New System.Threading.Thread(AddressOf listen) 'initialize a new thread for the listener so our GUI doesn't lag
listener.IsBackground = True
listener.Start(CInt(IncomingPortString)) 'start the listener, with the port specified as a parameter (textbox1 is our port textbox)
Catch ex As Exception
txtSystemMessages_AddText(String.Format("Error in formMain_Load sub: {0}{1}", ex.Message.ToString, vbNewLine))
End Try
End Sub
Sub listen(ByVal port As Integer)
Try
Dim t As New TcpListener(IPAddress.Any, port) 'declare a new tcplistener
t.Start() 'start the listener
Do
Dim client As New ConnectedClient(t.AcceptTcpClient) 'initialize a new connected client
AddHandler client.gotmessage, AddressOf received 'add the handler which will raise an event when a message is received
AddHandler client.disconnected, AddressOf disconnected 'add the handler which will raise an event when the client disconnects
Loop Until False
Catch ex As Exception
txtSystemMessages_AddText(String.Format("Error in Listen sub: {1}{2}", ex.Message.ToString, vbNewLine))
End Try
End Sub
Sub received(ByVal msg As String, ByVal client As ConnectedClient)
Try
If Not clients.ContainsKey(client) Then
clients.Add(client, client.name.ToString) 'add the client to our hashtable
End If
Catch ex As ArgumentException
End Try
(The sub that processes the incoming data string "msg".)
End Sub
I'm at a complete loss to know what could be causing this issue, and a threading issue is all that I can think of. Could a different machine have different threading schemes? Any help would be greatly appreciated.
I'm working on a remote control tool. The client runs a program to locally send commands to servers in order to control them.
However, the client doesn't know the server's IP address and vice versa.
I decided to use UDP broadcasting (please tell me if there's a better way to do this, I tried using multicast but I didn't really understand it). When started, the client (which controls the servers) broadcasts a message to tell the servers that a new client connected. Then (or when the server is started), the servers broadcast their own IP addresses. When the client receives an IP address, it tries to connect via TCP.
Unfortunately, I ran into problems with that. I randomly got An existing connection was forcibly closed by the remote host exceptions and I wasn't able to find out why.
The exception occurred in my client program when listening for UDP broadcasts.
Now, I'm looking for a better way to find the clients.
Should I use broadcast or multicast?
How would I implement that?
EDIT: It wouldn't be a problem to use multiple ports. However, I need to be able to run a client AND a server on a single computer.
Here's the code I was using
Client (controls servers)
'Variables
Private UdpBroadcaster As UdpClient
Private UdpBroadcasterEndpoint As New IPEndPoint(IPAddress.Broadcast, 4334)
'Sub New()
Try
UdpBroadcaster = New UdpClient(4333)
UdpBroadcaster.EnableBroadcast = True
Catch
MsgBox("Error creating UDP client! Port already in use?", ...)
End Try
'Called when the application starts
Private Sub StartUdpListener()
Dim ListenerUdp As New Thread(AddressOf UdpListener)
ListenerUdp.IsBackground = True
ListenerUdp.Start()
End Sub
'Started as thread in StartUdpListener()
Private Sub UdpListener()
Try
Do
'The next line fails with the error I described (An existing connection was forcibly closed by the remote host)
Dim ReceivedBytes() As Byte = UdpBroadcaster.Receive(UdpBroadcasterEndpoint)
Dim ReceivedString As String = System.Text.Encoding.UTF32.GetString(ReceivedBytes)
'The following three lines will just connect to the received hostname
Dim ScanThread As New Thread(Sub() ScanSingle(ReceivedString))
ScanThread.IsBackground = True
ScanThread.Start()
Loop
Catch
If Not UdpBroadcaster Is Nothing Then
UdpBroadcaster.Close()
UdpBroadcaster = Nothing
End If
InvokeStatus("UDP connection lost, please try again later.")
End Try
End Sub
'Called when the application starts and when the user manually clicks the "UDP Scan" button
Private Sub StartBroadcastUdpThread()
Dim UdpBroadcastThread As New Thread(Sub() BroadcastUdp())
UdpBroadcastThread.IsBackground = True
UdpBroadcastThread.Start()
End Sub
'Started as thread in StartBroadcastUdpThread()
Private Sub BroadcastUdp()
If UdpBroadcaster Is Nothing Then
Try
UdpBroadcaster = New UdpClient(4333)
UdpBroadcaster.EnableBroadcast = True
Catch
MsgBox("Error creating UDP Client.", MsgBoxStyle.Critical, "Error")
Application.Exit()
Return
End Try
End If
Dim BroadcastBytes() As Byte = System.Text.Encoding.UTF32.GetBytes("Client-Identify")
UdpBroadcaster.Send(BroadcastBytes, BroadcastBytes.Length, UdpBroadcasterEndpoint)
InvokeStatus("UDP request sent successfully")
End Sub
Servers (controlled by client)
'Variables
Private UdpBroadcaster As UdpClient
Private UdpBroadcasterEndpoint As New IPEndPoint(IPAddress.Broadcast, 4333)
'Main method
Public Sub Main()
Try
UdpBroadcaster = New UdpClient(4334)
UdpBroadcaster.EnableBroadcast = True
StartUdpListener()
StartBroadcastUdpThread()
Catch
Console.WriteLine("Failed to create server. Port already in use?")
End Try
End Sub
'Called in Main()
Private Sub StartUdpListener()
Dim ListenerUdp As New Thread(AddressOf UdpListener)
ListenerUdp.IsBackground = True
ListenerUdp.Start()
End Sub
'Started as thread in StartUdpListener()
Private Sub UdpListener()
Try
Do
Dim ReceivedBytes() As Byte = UdpBroadcaster.Receive(UdpBroadcasterEndpoint)
Dim ReceivedString As String = System.Text.Encoding.UTF32.GetString(ReceivedBytes)
If ReceivedString.Equals("Client-Identify") Then
StartBroadcastUdpThread()
End If
Loop
Catch
If Not UdpBroadcaster Is Nothing Then
UdpBroadcaster.Close()
End If
End Try
End Sub
'Called when the application is started or a "Client-Identify" command is received
Private Sub StartBroadcastUdpThread()
Dim UdpBroadcastThread As New Thread(Sub() BroadcastUdp())
UdpBroadcastThread.IsBackground = True
UdpBroadcastThread.Start()
End Sub
'Started as thread in StartBroadcastUdpThread()
Private Sub BroadcastUdp()
Dim BroadcastBytes() As Byte = System.Text.Encoding.UTF32.GetBytes(Dns.GetHostName)
UdpBroadcaster.Send(BroadcastBytes, BroadcastBytes.Length, UdpBroadcasterEndpoint)
End Sub
Thanks in advance!
Thank you for your answers. I fixed it by removing the feature to manually call StartBroadcastUdpThread() in my client.
I still don't understand why this happens though. I use exactly the same code for both client and server, except the ports are swapped. The TCP server doesn't crash even if the StartBroadcastUdpThread() method is called multiple times, the client does. By the way, the problem occurs regardless of whether the client or server is started first.
Even if I don't really understand why broadcasting the second time stops the client from receiving broadcasts - it's fixed for now. Thanks for you help!
I would suggest using Zeroconf to find the server and clients, and then use a TCP socket to communicate between the two. You can see an example implementation on key-value pair zeroconf announcements here: https://github.com/Eyescale/Lunchbox/blob/master/lunchbox/servus.cpp
Minimal UDP server basis:
Imports System.Threading
Shared client As UdpClient
Shared receivePoint As IPEndPoint
client = New UdpClient(2828) 'Port
receivePoint = New IPEndPoint(New IPAddress(0), 0)
Dim readThread As Thread = New Thread(New ThreadStart(AddressOf WaitForPackets))
readThread.Start()
Public Shared Sub WaitForPackets()
While True
Dim data As Byte() = client.Receive(receivePoint)
Console.WriteLine("=" + System.Text.Encoding.ASCII.GetString(data))
End While
End Sub
I'm realizing a .NET chat application but i still have that error:
I can send only a message per connection.
For example. With the code below, i can send only one message that can be received correctly by the other peer, but if i send another message message, on the same connection,it won't be received by the remote PC.
Here is the code:
Dim client_TCP As New TcpClient
Private Sub send_obj(ByVal obj As Object)
Dim bf As New BinaryFormatter
Dim tosend As Packet
tosend.data = obj
bf.Serialize(client_TCP.GetStream(), tosend)
client_TCP.GetStream.Flush()
End Sub
Private Sub connect_to_port()
Try
client_TCP = New TcpClient(client_data.getIP(), client_data.getPort())
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Private Sub disconnect_from_port()
client_TCP.Close()
End Sub
And here is the listener:
Private Sub Timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timer.Tick
If client_TCP_listener.Pending = True Then
....
End If
End Sub
So, to send a message I always need to do this (example):
Dim b As Byte
b = 1
disconnect_from_port()
connect_to_port()
client_TCP.GetStream().WriteByte(b)
client_TCP.GetStream().Flush()
I tried to put\remove the flush from both the code. Nothing happened.
Have you got any ideas?!
How do you know that it is not received? Did you try emulating remote host with your own code?
TCP is a stream protocol that means that you can send two bytes doing two separate calls to client_TCP.GetStream().WriteByte(b) and the remote party can receive those 2 bytes using one Receive call. You should not make any assumptions on the I/O API call patterns (number of writes and number of receives) but analyze the data you're sending receiving via stream connection.
So to send messages using stream protocol you have to introduce the notion of the application protocol. For instance [2bytes-size][size-bytes of message] - which means that if we want to send "hello" message we at first will send 2 bytes containing the size of the "hello" string and then the string itself.
make sure that receiving end is also using .net BinaryFormatter for deserlizing the object.