Asynchronous Socket Server Question

G

Guest

I am trying to create a socket server which will listen for connections from
multiple clients and call subroutines in a Fortran DLL and pass the results
back to the client. The asynchronous socket client and asynchronous socket
server example code provided in the .NET framework developers guide is a
great start but I have not dealt with sockets before and I am struggling with
something.

From what I can tell the sample server code provided will only listen to
one incomming connection at a time and the backlog can be set to allow more
connections to que up ready for processing when the current connection is
completed.


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

' Start an asynchronous socket to listen for connections.
Console.WriteLine("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


While the documentation indicates that connections to an asychronous socket
may be completed in a different order than that in which they were recieved,
it appears to me that the listener will only accept a connection is when the
allDone.Set event occurs and the loop can start a new iteration.

What I would like to happen is:

Accept input request (0)
on the thread created to receive request(0) perform the call to my Fortran
DLL and return the output to the client.

While request(0) is being processed on its own thread the main thread should
be able to accept input request(1)

on the thread created to receive request(1) perform the call to my Fortran
DLL and return the output to the client.

While request(0) and request(1) are being processed on their own threads the
main thread should be able to accept input request(2)

etc.

Am I off base?
How can I get more than one thread reading input from the socket at the same
time?

Thanks,
Erik
 
T

Tom Shelton

Engineerik said:
I am trying to create a socket server which will listen for connections from
multiple clients and call subroutines in a Fortran DLL and pass the results
back to the client. The asynchronous socket client and asynchronous socket
server example code provided in the .NET framework developers guide is a
great start but I have not dealt with sockets before and I am struggling with
something.

From what I can tell the sample server code provided will only listen to
one incomming connection at a time and the backlog can be set to allow more
connections to que up ready for processing when the current connection is
completed.


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

' Start an asynchronous socket to listen for connections.
Console.WriteLine("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


While the documentation indicates that connections to an asychronous socket
may be completed in a different order than that in which they were recieved,
it appears to me that the listener will only accept a connection is when the
allDone.Set event occurs and the loop can start a new iteration.

What I would like to happen is:

Accept input request (0)
on the thread created to receive request(0) perform the call to my Fortran
DLL and return the output to the client.

While request(0) is being processed on its own thread the main thread should
be able to accept input request(1)

on the thread created to receive request(1) perform the call to my Fortran
DLL and return the output to the client.

While request(0) and request(1) are being processed on their own threads the
main thread should be able to accept input request(2)

etc.

Am I off base?

Yes :) I don't mean that in a mean way.
How can I get more than one thread reading input from the socket at the same
time?

Just follow the async example. It does exactly that. See, the way a
server socket works is that it is bound to a particular port. When a
client comes in, the accept socket call returns with a handle to a new
socket - in other words, communication does not take place over the
server socket. The listener is simply a means for allowing clients to
connect to a known endpoint, once connected they will not be
communicating on the same port as the server.

In psuedo code, syncrounous sockets look something like:

while (true)
socket client = server.accept () ' blocks until there are pending
connections
spawnthread (client) ' pas the new socket to a thread for processing
wend

This is what the async calls are doing... Only it doesn't wait for
accept to return, it uses the event to signal when it can call accept
again (there can only be one accept at a time). Now you are right that
there is a queue for new connections - a server can only accept one
connection at a time, and that is what the backlog does is set the max
size of that queue before the server socket refuses to allow the
connection. I hope I'm making this clear...
 
G

Guest

Thanks for the explanation, however...
Two more related questions,
In the read callback,
Public Shared Sub ReadCallback(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.
Dim bytesRead As Integer = handler.EndReceive(ar)

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

' Check for end-of-file tag. If it is not there, read
' more data.
content = state.sb.ToString()
If content.IndexOf("<EOF>") > -1 Then
' All the data has been read from the
' client. Display it on the console.
Console.WriteLine("Read {0} bytes from socket. " + vbLf + "
Data : {1}", content.Length, content)
' Echo the data back to the client.
Send(handler, content)
Else
' Not all data received. Get more.
handler.BeginReceive(state.buffer, 0,
StateObject.BufferSize, 0, New AsyncCallback(AddressOf ReadCallback), state)
End If
End If
End Sub 'ReadCallback

Question 1
Is there a good way to determine when the full string has been read other
than searching for some end-of-input-flag like the "<EOF>"?

Question 2 (This really is the crux of my question)
How do I respond to the client if the user fails to include "<EOF>" in the
string passed to the server? The sample code has no timeout so the client
just waits forever and never gets any reply from the server.

I made 2 different client exes
Client1 does not pass "<EOF>" at the end of the string.
Client2 includes "<EOF>"

If I run client1 first then run client2 client1 waits forever because
Send(handler,content) never gets called. However, client 2 also never
returns. That is why I asked my first question. Clearly, client2 input is
not getting processed because the main thread is blocked waiting for the
client1 thread to call alldone.set which will never happen.

This leads me to think that if client1 sent a valid but time consuming
request then the server would block until the client1 request was completed
before it would do anything with the client2 request which may have been
simple and should have returned to client2 long before the request from
client1 finished being processed.
 
G

Guest

Engineerik said:
I made 2 different client exes
Client1 does not pass "<EOF>" at the end of the string.
Client2 includes "<EOF>"

If I run client1 first then run client2 client1 waits forever because
Send(handler,content) never gets called. However, client 2 also never
returns. That is why I asked my first question. Clearly, client2 input is
not getting processed because the main thread is blocked waiting for the
client1 thread to call alldone.set which will never happen.

This leads me to think that if client1 sent a valid but time consuming
request then the server would block until the client1 request was completed
before it would do anything with the client2 request which may have been
simple and should have returned to client2 long before the request from
client1 finished being processed.

OK, Sorry to be so dense on the blocking issue.
I realize from your comments that I needed to move the alldone.reset to the
AcceptCallback sub instead of leaving it in the ReadCallback. The sample
code should probably have it there also in order to represent a truely
asynchronous server.

I am still wondering though how to deal with input which omits the "<EOF>".
I would like to be able to send some sort of error message back to the client
in that case.

Thanks for the assistance.
Erik
 
G

Guest

Engineerik said:
Question 1
Is there a good way to determine when the full string has been read other

AHA!
I think I just found the answer to that...
if handler.available = 0 then all bytes passes from the client have been
accepted by the server.

Erik
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top