digitalmars.D.learn - Socket and SocketStream
- Kyle Mallory (121/121) Apr 04 2010 I'm trying a bit of socket stuff. I went back to the htmlget.d sample,
- Kyle Mallory (17/138) Apr 05 2010 I hate replying to my own thead. :-(
- Jesse Phillips (3/3) Apr 05 2010 I believe you are running into this bug:
- Kyle Mallory (6/9) Apr 05 2010 Argh.. Thanks. Looks like an easy enough patch. Unfortunate the bug
- Kyle Mallory (5/8) Apr 05 2010 Thank you, Jesse! Applied the patch, recompiled libdruntime.a and
I'm trying a bit of socket stuff. I went back to the htmlget.d sample, and patched it up for 2.0 (I'm using DMD 2.042 on Ubuntu 9.10). I get the same results from this as I do from my own code, which is that writeString() on the SocketStream throws an exception. From everything I can tell, I don't have an established connection, even though everything claims I have one. Here is the updated sample code: /* HTMLget written by Christopher E. Miller This code is public domain. You may use it for any purpose. This code has no warranties and is provided 'as-is'. */ //debug = HTMLGET; module htmlget; import std.string, std.conv, std.stream; import std.socket, std.socketstream; import std.stdio; int main(string[] args) { uint addr; if(args.length < 2) { printf("Usage:\n htmlget <web-page>\n"); return 0; } string url = args[1]; int i; //i = std.string.find(url, "://"); i=std.string.indexOf(url,"://"); if(i != -1) { if(icmp(url[0 .. i], "http")) throw new Exception("http:// expected"); } url = url[i+3 .. url.length]; if(i != -1) // Remove anchor ref. url = url[0 .. i]; //i = std.string.find(url, '/'); i=std.string.indexOf(url,'/'); string domain; if(i == -1) { domain = url; url = "/"; } else { domain = url[0 .. i]; url = url[i .. url.length]; } ushort port; //i = std.string.find(domain, ':'); i = std.string.indexOf(domain,':'); if(i == -1) { port = 80; // Default HTTP port. } else { port=parse!(ushort)(domain[i+1..domain.length]); domain = domain[0 .. i]; } writefln("Parsed domain: %s, port: %d and url: %s", domain, port, url); addr = InternetAddress.parse(domain); debug(HTMLGET) writefln("Connecting to %s on port %d...", domain, port); auto Socket sock = new TcpSocket(new std.socket.InternetAddress(addr/*domain*/, port)); Stream ss = new SocketStream(sock); debug(HTMLGET) printf("Connected!\nRequesting URL \"" ~ url ~ "\"...\n"); if(port != 80) { char[] temp=cast(char[]) domain; temp=temp~cast(char[])":" ~cast(char[]) (to!string(port)); domain=cast(string)temp; } ss.writeString("GET " ~ url ~ " HTTP/1.1\r\n" "Host: " ~ domain ~ "\r\n" "\r\n"); // Skip HTTP header. string line; for(;;) { line = cast(string)ss.readLine(); if(!line.length) break; const string CONTENT_TYPE_NAME = "Content-Type: "; if(line.length > CONTENT_TYPE_NAME.length && !icmp(CONTENT_TYPE_NAME, line[0 .. CONTENT_TYPE_NAME.length])) { string type; type = line[CONTENT_TYPE_NAME.length .. line.length]; if(type.length <= 5 || icmp("text/", type[0 .. 5])) throw new Exception("URL is not text"); } } print_lines: while(!ss.eof()) { line = cast(string)ss.readLine(); printf("%.*s\n", line); size_t iw; for(iw = 0; iw != line.length; iw++) { if(!icmp("</html>", line[iw .. line.length])) break print_lines; } } return 0; } And here is my invocation, and its response: $ dmd -run ./htmlget2.d http://10.120.1.106:80/ Parsed domain: 10.120.1.106, port: 80 and url: / std.stream.WriteException: unable to write to stream $ Can anyone else duplicate this? Or let me know if I'm doing something wrong in my updating of the sample code?
Apr 04 2010
I hate replying to my own thead. :-( I was able to compile listener.d, and connect successfully to it via telnet., so I know at least the listener stuff so working. However, stepping down to an even simpler example, I can't even get the following code to establish a connection: import std.socket; void main(string[] args) { Socket s = new TcpSocket(new InternetAddress(args[1], parse!(ushort)(args[2]))); assert(s.isAlive); s.close(); } Connecting against listener.d, I should at least see a "connection from" and a "disconnected". But nothing happens. No error messages, no exceptions, etc. Am I the only one with this problem? On 04/04/2010 11:36 AM, Kyle Mallory wrote:I'm trying a bit of socket stuff. I went back to the htmlget.d sample, and patched it up for 2.0 (I'm using DMD 2.042 on Ubuntu 9.10). I get the same results from this as I do from my own code, which is that writeString() on the SocketStream throws an exception. From everything I can tell, I don't have an established connection, even though everything claims I have one. Here is the updated sample code: /* HTMLget written by Christopher E. Miller This code is public domain. You may use it for any purpose. This code has no warranties and is provided 'as-is'. */ //debug = HTMLGET; module htmlget; import std.string, std.conv, std.stream; import std.socket, std.socketstream; import std.stdio; int main(string[] args) { uint addr; if(args.length < 2) { printf("Usage:\n htmlget <web-page>\n"); return 0; } string url = args[1]; int i; //i = std.string.find(url, "://"); i=std.string.indexOf(url,"://"); if(i != -1) { if(icmp(url[0 .. i], "http")) throw new Exception("http:// expected"); } url = url[i+3 .. url.length]; if(i != -1) // Remove anchor ref. url = url[0 .. i]; //i = std.string.find(url, '/'); i=std.string.indexOf(url,'/'); string domain; if(i == -1) { domain = url; url = "/"; } else { domain = url[0 .. i]; url = url[i .. url.length]; } ushort port; //i = std.string.find(domain, ':'); i = std.string.indexOf(domain,':'); if(i == -1) { port = 80; // Default HTTP port. } else { port=parse!(ushort)(domain[i+1..domain.length]); domain = domain[0 .. i]; } writefln("Parsed domain: %s, port: %d and url: %s", domain, port, url); addr = InternetAddress.parse(domain); debug(HTMLGET) writefln("Connecting to %s on port %d...", domain, port); auto Socket sock = new TcpSocket(new std.socket.InternetAddress(addr/*domain*/, port)); Stream ss = new SocketStream(sock); debug(HTMLGET) printf("Connected!\nRequesting URL \"" ~ url ~ "\"...\n"); if(port != 80) { char[] temp=cast(char[]) domain; temp=temp~cast(char[])":" ~cast(char[]) (to!string(port)); domain=cast(string)temp; } ss.writeString("GET " ~ url ~ " HTTP/1.1\r\n" "Host: " ~ domain ~ "\r\n" "\r\n"); // Skip HTTP header. string line; for(;;) { line = cast(string)ss.readLine(); if(!line.length) break; const string CONTENT_TYPE_NAME = "Content-Type: "; if(line.length > CONTENT_TYPE_NAME.length && !icmp(CONTENT_TYPE_NAME, line[0 .. CONTENT_TYPE_NAME.length])) { string type; type = line[CONTENT_TYPE_NAME.length .. line.length]; if(type.length <= 5 || icmp("text/", type[0 .. 5])) throw new Exception("URL is not text"); } } print_lines: while(!ss.eof()) { line = cast(string)ss.readLine(); printf("%.*s\n", line); size_t iw; for(iw = 0; iw != line.length; iw++) { if(!icmp("</html>", line[iw .. line.length])) break print_lines; } } return 0; } And here is my invocation, and its response: $ dmd -run ./htmlget2.d http://10.120.1.106:80/ Parsed domain: 10.120.1.106, port: 80 and url: / std.stream.WriteException: unable to write to stream $ Can anyone else duplicate this? Or let me know if I'm doing something wrong in my updating of the sample code?
Apr 05 2010
I believe you are running into this bug: http://d.puremagic.com/issues/show_bug.cgi?id=2835 Where sockets don't work in Linux.
Apr 05 2010
On 04/05/2010 06:56 PM, Jesse Phillips wrote:I believe you are running into this bug: http://d.puremagic.com/issues/show_bug.cgi?id=2835 Where sockets don't work in Linux.Argh.. Thanks. Looks like an easy enough patch. Unfortunate the bug its still lingering in the latest build (especially considering that a patch is provided). I guess the next step is figuring out how to rebuild the phobos library. Thanks.
Apr 05 2010
On 04/05/2010 06:56 PM, Jesse Phillips wrote:I believe you are running into this bug: http://d.puremagic.com/issues/show_bug.cgi?id=2835 Where sockets don't work in Linux.Thank you, Jesse! Applied the patch, recompiled libdruntime.a and libphobos2.a and everything is working as expected! Very much appreciated! Kyle
Apr 05 2010