Exiting blocked threads (socket.accept)
Tim
tim at unknownMailAddress.com
Thu Mar 28 10:57:45 PDT 2013
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.
More information about the Digitalmars-d-learn
mailing list