On Thursday, 28 March 2013 at 12:28:05 UTC, Martin Drasar wrote:
On 28.3.2013 11:23, Tim wrote:
Thanks Martin and Ali. Your solution works as long as I use the
receive()-method, but what about using SocketStreams? I replaced socket.receive() with socketStream.readLine() which isn't broken by the
solution above...

If you check the documentation, you will see that the SocketStream is a
stream for blocking socket. You can't easily make it work with
nonblocking select() calls.

However, if you want to use the stream interface, you can write the non-blocking stream yourself. If you check the SocketStream at github
(https://github.com/D-Programming-Language/phobos/blob/master/std/socketstream.d),
you will see that it is pretty small and easy. You can transfer the
interrupt code inside the readBlock() method.

However, it will probably be for the best to just write your own method
to read for socket until the end of the line.

Martin

Thanks for everything, but I'm still having some problems with this solution... I implemented a simple ftp server which looks as follows:

import std.socket;
import core.thread;
import core.stdc.signal;
import std.stdio;
import std.string;
import std.conv : to;

__gshared Socket readSock;
__gshared Socket writeSock;
__gshared bool stopServer = false;

class DataChannel {
        Socket datasocket;
        this() {
                datasocket = new TcpSocket();
                datasocket.bind(new InternetAddress(0));
                datasocket.listen(0);
        }

}

class Connection : Thread {
  private Socket pSocket;
  void run() {
int i = 0x00;
DataChannel datachannel;
    ptrdiff_t received;
    ubyte[0x20] buffer;

    SocketSet ss = new SocketSet();

        pSocket.send("220 FTP ready.\r\n");
datachannel = new DataChannel();
  mainloop:
    while(1) {
i++;
      ss.reset();
      ss.add(pSocket);
      ss.add(readSock);

      if (Socket.select(ss, null, null) > 0) {

        if (ss.isSet(pSocket))
        {
          received = pSocket.receive(buffer);

        if (i == 1)
          pSocket.send("331 Password required for anyUser\r\n");
        else if (i == 2)
                pSocket.send("230 User anyUser logged in\r\n");
        else if (i == 3)
                pSocket.send("257 / is the current directory.\r\n");
        else if (i == 4)
                pSocket.send("215 UNIX Type: L8\r\n");
        else if (i == 5)
                pSocket.send("200 Type set to I\r\n");
        else if (i == 6) {
                string[] lip = split(pSocket.localAddress.toAddrString, ".");
auto port = (cast(InternetAddress) datachannel.datasocket.localAddress).port; pSocket.send("227 Entering Passive Mode(" ~ lip[0x00] ~ "," ~ lip[0x01] ~ "," ~ lip[0x02] ~ "," ~ lip[0x03] ~ "," ~ to!(string)(port / 256) ~ "," ~ to!(string)(port % 256) ~ ")\r\n");
                }
        else if (i == 7)
pSocket.send("150 Here comes the directory listing.\r\n226 Directory listing complete\r\n");
        else if (i == 8)
                pSocket.send("250 CWD command successful.\r\n");
        else if (i == 9)
                pSocket.send("257 / is the current directory.\r\n");
        }

          // process data
        }
        else if (ss.isSet(readSock))
        {
          writeln("Received interrupt");
          break mainloop;
        }
      }

    pSocket.close();
  }
  this(Socket s) {
    super(&run);
    pSocket = s;
  }
}

extern (C) void terminateServer(int s) nothrow {
  stopServer = true;
}

void main() {

  signal(SIGINT, &terminateServer);

  TcpSocket s = new TcpSocket();
  s.bind(new InternetAddress(2100));
  s.listen(0);

  auto pair = socketPair();

  readSock  = pair[0];
  writeSock = pair[1];

  SocketSet ss = new SocketSet();

  while (!stopServer)
  {
    ss.reset();
    ss.add(s);

    if (Socket.select(ss, null, null, dur!"msecs"(20)) > 0)
    {
      writeln("Received new connection");
      (new Connection(s.accept)).start();
    }
  }

  writeSock.send([1]);

  s.shutdown(SocketShutdown.BOTH);
  s.close();

  writeln("Finished");
}

I know... that's not only a dirty solution, but a terrible (and wrong) solution, but it's for demonstration purposes only. By connecting to this server using a ftp client (let's say FileZilla or gFTP), I can connect until I get an error (which comes because of the dirty solution... but that's not the point here). When I press CTRL+C to terminate the server, this doesn't work anymore. I don't know why (probably because of the datachannel? But there is no loop or something else in the datachannel-class - no accept() or similar)... I've a rfc959-based implemented version of the ftp-server, but the result is the same... pressing CTRL+C doesn't work in some cases.

Reply via email to