www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Creating a C# like Asynchronous Socket

reply DrCataclysm <4002600 ba-glauchau.de> writes:
I am trying to build something like the asynchronous Sockets from 


My code is something like this:


public class TCPListener {

     ushort _port;
     string _address;
     bool _active;
     string _lineEnd;
     ubyte[] _messageBuffer;
     Socket _socket;
     Socket _connection;
     int _waitForAnswer = 500;
     bool _keepOpen = true;

     this(string address, ushort port, string lineEnd = "\n") {
         _port = port;
         _address = address;
         _socket = new TcpSocket();
         _socket.setOption(SocketOptionLevel.SOCKET, 
SocketOption.REUSEADDR, true);
         this.connect(&this.Accepted);
         this.connect(&this.Received);
     }

     void startListening(){
     	try{
	        _socket.bind(new InternetAddress(_port));
	        _socket.listen(3);
     	}
     	catch (Exception e){
     		writeln(e.msg);
     	}
         auto _connectionTask = task(&this.Accept);
         _connectionTask.executeInNewThread();
     }

     private void Accept(){
         bool error = false;
         // try to accept connection
         try{
             Socket client = _socket.accept();
             Thread.sleep( dur!("msecs")( 50 ) );
             MessageBuffer buffer;
             auto received = client.receive(buffer.data);
             emit(error);
             //_connection = client;
         }
         catch (SocketAcceptException e){
             writeln("Error while accepting connection: " ~ e.msg);
             error = true;
         }public class TCPListener {

     ushort _port;
     string _address;
     bool _active;
     string _lineEnd;
     ubyte[] _messageBuffer;
     Socket _socket;
     Socket _connection;
     int _waitForAnswer = 500;
     bool _keepOpen = true;

     this(string address, ushort port, string lineEnd = "\n") {
         _port = port;
         _address = address;
         _socket = new TcpSocket();
         _socket.setOption(SocketOptionLevel.SOCKET, 
SocketOption.REUSEADDR, true);
         this.connect(&this.Accepted);
         this.connect(&this.Received);
     }

     void startListening(){
     	try{
	        _socket.bind(new InternetAddress(_port));
	        _socket.listen(3);
     	}
     	catch (Exception e){
     		writeln(e.msg);
     	}
         auto _connectionTask = task(&this.Accept);
         _connectionTask.executeInNewThread();
     }

     private void Accept(){
         bool error = false;
         // try to accept connection
         try{
             Socket client = _socket.accept();
             Thread.sleep( dur!("msecs")( 50 ) );
             MessageBuffer buffer;
             auto received = client.receive(buffer.data);
             emit(error);
             //_connection = client;
         }
         catch (SocketAcceptException e){
             writeln("Error while accepting connection: " ~ e.msg);
             error = true;
         }
         finally{
             emit(error);
         }
     }

     mixin Signal!(bool);

         finally{
             emit(error);
         }
     }

     mixin Signal!(bool);

...
}


The client created by _socket.accept() cannot receive any data.

client.receive() immediately returns 0 like a non-blocking 
socket. I think it has something to do with the original socket 
being owned by a different thread.

I am not very familiar with multitasking/multithreading in D so 
any help would be appreciated.
Nov 05 2017
parent reply DrCataclysm <4002600 ba-glauchau.de> writes:
On Sunday, 5 November 2017 at 14:47:37 UTC, DrCataclysm wrote:
 I am trying to build something like the asynchronous Sockets 

 
 ....

 The client created by _socket.accept() cannot receive any data.

 client.receive() immediately returns 0 like a non-blocking 
 socket. I think it has something to do with the original socket 
 being owned by a different thread.

 I am not very familiar with multitasking/multithreading in D so 
 any help would be appreciated.
// I removed all multithreading and cleaned up the example. It still does not work. // Sockets don't seem to work as class fields, is there a reason for this? // Has anyone a better idea to accomplish this? import std.socket; import std.stdio; void main(){ TCPListener test = new TCPListener("127.0.0.1", 9001); test.startListening(); while (true){} } public class TCPListener { ushort _port; string _address; bool _active; Socket _socket = null; Socket _connection = null; this(string address, ushort port, string lineEnd = "\n") { _port = port; _address = address; _socket = new TcpSocket(); _socket.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true); } void startListening(){ // bind the port in the main thread try{ assert(_socket !is null); _socket.bind(new InternetAddress(_port)); _socket.listen(3); } catch (Exception e){ writeln(e.msg); } //auto _connectionTask = task(&this.Accept); //_connectionTask.executeInNewThread(); Accept(); } private void Accept(){ bool error = false; // start accepting in a different thread try{ _connection = _socket.accept(); assert(_connection !is null); // this works ubyte[] buffer; // this does not block, even if the socket is explicitly markes // as blocking auto receive = _connection.receive(buffer); // this always fails assert(receive != 0); } catch (SocketAcceptException e){ writeln("Error while accepting connection: " ~ e.msg); error = true; } finally{ //emit(error); } } }
Nov 06 2017
parent DrCataclysm <4002600 ba-glauchau.de> writes:
On Monday, 6 November 2017 at 08:03:23 UTC, DrCataclysm wrote:
 On Sunday, 5 November 2017 at 14:47:37 UTC, DrCataclysm wrote:
 I am trying to build something like the asynchronous Sockets 

 
 ....

 The client created by _socket.accept() cannot receive any data.

 client.receive() immediately returns 0 like a non-blocking 
 socket. I think it has something to do with the original 
 socket being owned by a different thread.

 I am not very familiar with multitasking/multithreading in D 
 so any help would be appreciated.
Found my error in the following lines:
             _connection = _socket.accept();
             assert(_connection !is null); // this works
             ubyte[] buffer;
             // as blocking
             auto receive = _connection.receive(buffer);
I forgot to give bugger a size. If not given, the compiler declares buffer.size as 0. receive writes data from the socket into the buffer and returns the length of the data. If the buffer is too small it only receives as much data as fits in the buffer. If the buffer is too small for any data it just returns with 0;
Nov 06 2017