Jump to content
  • Advertisement
Sign in to follow this  
Sirisian

[.net] [VB.NET] Asychronous Multi-Client TCP Server [solved]

This topic is 3789 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

//Edit fixed don't worry about it: //I figured it out. It wasn't actually too much a problem of my code. It was //just how flash handled security files. It closed the socket afterwards on me I made a multi-client TCP server a while ago, but it is riddled with bugs and is all together unstable due to my ignorance. I recently started working again on the project, but I want to do it right this time. This is for a small multiplayer game server and all I need is a tutorial or something that shows how to correctly create and manage asynchronous sockets. Along with that I need the tutorial to have error checking code. (needless to say my old server just had random Try Catch statements everywhere hoping to catch an error). Basically something that show 100% how I'm so supposed to setup the listening socket and have a call back to a connection request function that connects that client to another socket. I've been googling hoping I didn't have to make a post, but I haven't found anything that show 100% how it's supposed to be setup. Did I miss something in the MSDN documentation about asynchronous multi-client TCP servers? Any help with this would be greatly appreciated. [Edited by - Sirisian on July 20, 2007 1:57:43 AM]

Share this post


Link to post
Share on other sites
Advertisement
Update: I code this with the help of some msdn information:

Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
Imports Microsoft.VisualBasic

' State object for reading client data asynchronously

Public Class StateObject
' Client socket.
Public workSocket As Socket = Nothing
' Size of receive buffer.
Public Const BufferSize As Integer = 1024
' Receive buffer.
Public buffer(BufferSize) As Byte
'To-Do: Make a reference to some playerdata
End Class 'StateObject


Public Class AsynchronousSocketListener
' Thread signal.
Public Shared allDone As New ManualResetEvent(False)
'Mutex
Private Shared mut As New Mutex()
'Clients
Public Shared clients As New List(Of StateObject)
'Log
Public Shared log As TextBox
Public mainThread As Thread

Delegate Sub WriteToLogDelegate(ByVal entry As String)

Public Sub New(ByRef log_ As TextBox)
log = log_
log.Text = "Asynchronous server socket initialized"
mainThread = New Thread(AddressOf Main)
mainThread.Start()
End Sub

'Delegate method to write to the data log
Public Shared Sub WriteToLogMethod(ByVal entry As String)
'log.Text.Insert(log.Text.Length - 2, Chr(13) & entry)
log.Text = log.Text & vbNewLine & entry
End Sub
'Simplified Subroutine to write to the data log
Public Shared Sub WriteToLog(ByVal entry As String)
Dim logDelegate As New WriteToLogDelegate(AddressOf WriteToLogMethod)
If log.InvokeRequired() Then
log.Invoke(logDelegate, entry)
Else
logDelegate(entry)
End If
End Sub

' This server waits for a connection and then uses asychronous operations to
' accept the connection, get data from the connected client
Public Shared Sub Main()
'mut.WaitOne()
'log.Text = "Started"
'mut.ReleaseMutex()

' Data buffer for incoming data.
Dim bytes() As Byte = New [Byte](1023) {}

' Establish the local endpoint for the socket.
Dim ipHostInfo As IPHostEntry = Dns.GetHostEntry(Dns.GetHostName())
Dim ipAddress As IPAddress = ipHostInfo.AddressList(0)
Dim localEndPoint As New IPEndPoint(ipAddress, 30303)

' Create a TCP/IP socket.
Dim listener As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)

' Bind the socket to the local endpoint and listen for incoming connections.
listener.Bind(localEndPoint)
listener.Listen(100)

While True
' Set the event to nonsignaled state.
allDone.Reset()

' Start an asynchronous socket to listen for connections.
WriteToLog("Waiting for a connection...")
listener.BeginAccept(New AsyncCallback(AddressOf AcceptCallback), listener)

' Wait until a connection is made and processed before continuing.
allDone.WaitOne()
End While
End Sub 'Main

Public Shared Sub AcceptCallback(ByVal ar As IAsyncResult)
' Get the socket that handles the client request.
Dim listener As Socket = CType(ar.AsyncState, Socket)
' End the operation.
Dim handler As Socket = listener.EndAccept(ar)

' Create the state object for the async receive.
Dim state As New StateObject
state.workSocket = handler
state.workSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, New AsyncCallback(AddressOf ReceiveCallback), state)

'Add the client socket to a list for easy reference: Note: Not sure if the mutex is necessary
mut.WaitOne()
clients.Add(state)
mut.ReleaseMutex()

WriteToLog("Connection")

'I HAVE NO IDEA WHERE TO PUT THIS allDone.Set()
'Signal the main thread to continue.
allDone.Set()
End Sub 'AcceptCallback

Public Shared Sub ReceiveCallback(ByVal ar As IAsyncResult)
Dim content As String = String.Empty

' Retrieve the state object and the handler socket
' from the asynchronous state object.
Dim state As StateObject = CType(ar.AsyncState, StateObject)
Dim handler As Socket = state.workSocket

' Read data from the client socket.
If (handler.Connected()) Then
Dim bytesRead As Integer = handler.EndReceive(ar)

If bytesRead > 0 Then
' There might be more data, so store the data received so far.
content = Encoding.ASCII.GetString(state.buffer, 0, bytesRead)

'Send the Security Policy Data If Flash 9 Requests it
Dim policyFileNeeded As Boolean = False
If content.Length >= 22 Then
If content.Substring(0, 22) = "<policy-file-request/>" Then
WriteToLog("Policy File Sent")
'<?xml version=" & Chr(34) & "1.0" & Chr(34) & "?><!DOCTYPE cross-domain-policy SYSTEM " & Chr(34) & "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd" & Chr(34) & ">
Send(handler, "<cross-domain-policy><allow-access-from domain=" & Chr(34) & "*" & Chr(34) & "to-ports=" & Chr(34) & "30303" & Chr(34) & "/></cross-domain-policy>")
policyFileNeeded = True
End If
End If
If Not policyFileNeeded Then
WriteToLog("Data Received: " & content)
Send(handler, "Data Received")
End If

End If
'Begin waiting to receive on the socket
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, New AsyncCallback(AddressOf ReceiveCallback), state)
End If
End Sub 'ReceiveCallback

Public Shared Sub Send(ByVal handler As Socket, ByVal data As String)
' Convert the string data to byte data using ASCII encoding.
Dim byteData As Byte() = Encoding.ASCII.GetBytes(Data)

' Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0, New AsyncCallback(AddressOf SendCallback), handler)
End Sub 'Send

Private Shared Sub SendCallback(ByVal ar As IAsyncResult)
' Retrieve the socket from the state object.
Dim handler As Socket = CType(ar.AsyncState, Socket)

' Complete sending the data to the remote device.
Dim bytesSent As Integer = handler.EndSend(ar)
Console.WriteLine("Sent {0} bytes to client.", bytesSent)

WriteToLog("Data Sent Bytes: " & bytesSent)

'handler.Shutdown(SocketShutdown.Both)
'handler.Close()

'I HAVE NO IDEA WHERE TO PUT THIS allDone.Set()
'Signal the main thread to continue.
'allDone.Set()
End Sub 'SendCallback

Public Sub PingAllClients()
'Not sure if the mutex is necessary
mut.WaitOne()
For i As UInteger = 0 To clients.Count - 1
Send(clients(i).workSocket, "ping")
Next
mut.ReleaseMutex()
End Sub 'PingAllClients

End Class 'AsynchronousSocketListener


Then on my form I just have

Public Class Main
Public SocketServer As AsynchronousSocketListener
Private Sub Main_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
SocketServer = New AsynchronousSocketListener(txtLog)
End Sub

Private Sub btnPingAllClients_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPingAllClients.Click
SocketServer.PingAllClients()
End Sub
End Class


So I just have button and text box on the form for logging/pinging tests

I can't seem to wrap my mind around what Mutex and the ManualResetEvent objects are. I keep reading the MSDN stuff but it's not clicking I guess...

Okay what's really messing with me is that it would seem I am not doing something with my sockets correctly. Mind you that this is for multiple clients. Is my AcceptCallback function correct? Something tells me it isn't. Either that or something is blocking. If I uncomment the lines:

'handler.Shutdown(SocketShutdown.Both)
'handler.Close()

For some reason the client says it connected. Then it disconnects as expected. I can't figure out why the client won't connect normally.

Again any information on the subject would be very helpful. This is seemingly very difficult for me to understand.

Share this post


Link to post
Share on other sites
For Flash Player 9.0.115 and superior:

Flash Player expect a policy file null terminated, in VB it is Chr(0)
then the code line with Send( policy file ) is:

Send(handler, "<cross-domain-policy><allow-access-from domain=" & Chr(34) & "*" & Chr(34) & "to-ports=" & Chr(34) & "30303" & Chr(34) & "/></cross-domain-policy>" & Chr(0) )


regards all

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!