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.