Exiting blocked threads (socket.accept)
Tim
tim at unknownMailAddress.com
Thu Mar 28 12:33:18 PDT 2013
On Thursday, 28 March 2013 at 17:57:47 UTC, Tim wrote:
> 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.
I should better double check the documentation... the reason for
the problem is the if-then-elseif... I've changed this to:
if (ss.isSet(pSocket)) {
// ... do stuff here
}
if (ss.isSet(readSock)) {
break mainloop;
}
As I already mentioned... thanks to Sean, Ali and Martin!
More information about the Digitalmars-d-learn
mailing list