www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Problem with SocketStream.readLine

reply Michael Butscher <mbutscher gmx.de> writes:
Hi,

could please somebody explain me why the following code doesn't work properly?

It was tested on Windows ME, so you have to link with ws2_32.lib to compile it.

The code starts 2 threads, a server and a client which communicate by a TCP 
socket. The client sends a single line (ending with "\r\n") as a request to the 
server, the server reads it and responds with exactly 100000 bytes of data, but 
the client receives only a part of the data.

Curiously, the code works perfectly well if the request string only ends with 
"\n".

After I replaced SocketStream.readLine() with a slightly modified function
which 
ignores "\r" characters, it worked also.

Thanks in advance


Michael




The code:
--------------------------------------------------

import std.socket;
import std.socketstream;
import std.stream;
import std.thread;


const char[] IP = "127.0.0.1";      // Address to use for connection
const int PORT = 2000;              // Port to use     
const int TESTLENGTH = 100000;      // Length of test data
const ubyte[TESTLENGTH] testbuffer; // Data to send from server to client



// Request string to send from client to server:

const char[] REQSTRING = "Testing\r\n";   // Does not work
// const char[] REQSTRING = "Testing\n";  // Works  (Missing '\r')




int serve()  // Server function
{
  auto Socket listener = new TcpSocket();
  listener.bind(new InternetAddress(IP, PORT));
  listener.listen(10);

  Socket sock;

  while (true)
  {
    try
    {
      sock = listener.accept();
      printf("Request\n");

      sock.blocking = true;

      SocketStream stream = new SocketStream(sock);

      stream.readLine();   // Read request

      int sent = stream.write(testbuffer);  // Send data
      
      sock.shutdown(SocketShutdown.BOTH);
      sock.close();
      printf("Sent: %i\n", sent);
    }
    catch (Exception exc)
    {
      printf("Server Error\n");
      exc.print();
    }
  }
}


void request()  // Client function
{
  while(true)
  {
    int i = 0;
    try
    {
      Socket sock = new TcpSocket(new InternetAddress(IP, PORT));
      SocketStream stream = new SocketStream(sock);

      char buffer;

      stream.write(cast(ubyte[])REQSTRING);  // Send request

      while(true)
      {
        stream.read(buffer);  // Read data
        ++i;
      }
    }
    catch (Exception exc)
    {
      printf("Read: %i\n", i);
    }
  }
}



int main(char[][] args)
{
  int runreq()
  {
    request();
    return 0;
  }

  int runserv()
  {
    serve();
    return 0;
  }

  Thread t;
  if (args.length == 1 || args[1] == "s")  // Server only
  {
    t = new Thread(&runserv);
    t.start();
  }

  if (args.length == 1 || args[1] == "c")  // Client only
  {
    t = new Thread(&runreq);
    t.start();
  }

  t.wait();

  return 0;
}


--------------------------------------------------
Apr 28 2005
next sibling parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
Interesting. I don't know much about sockets but the socketstream.readline 
doesn't read the last \n when it sees the \r - it leaves it in the stream 
until the next read. I assume that's because readLine doesn't actually know 
if there is a \n coming and it doesn't want to block waiting for one. It 
seems, though, that leaving that char in the stream gets in the way of 
future send/recv calls. It doesn't matter what that last char is or if it 
just reads an incomplete amount of data. Is there a way to know if the line 
ending is \r or \r\n ahead of time or is there some setting on the socket 
that will fix it? Again I don't know the details of how sockets send and 
recieve so someone else besides me will have to help out (I generally take 
generic stream questions but this one seems out of my realm).

"Michael Butscher" <mbutscher gmx.de> wrote in message 
news:MPG.1cdb6332bdc3cce0989681 news.digitalmars.com...
 Hi,

 could please somebody explain me why the following code doesn't work 
 properly?

 It was tested on Windows ME, so you have to link with ws2_32.lib to 
 compile it.

 The code starts 2 threads, a server and a client which communicate by a 
 TCP
 socket. The client sends a single line (ending with "\r\n") as a request 
 to the
 server, the server reads it and responds with exactly 100000 bytes of 
 data, but
 the client receives only a part of the data.

 Curiously, the code works perfectly well if the request string only ends 
 with
 "\n".

 After I replaced SocketStream.readLine() with a slightly modified function 
 which
 ignores "\r" characters, it worked also.

 Thanks in advance


 Michael
Apr 28 2005
parent reply "Charlie" <charles jwavro.com> writes:
Hmm, win32 and linux both use \n as the 'last' char to denote a new line,
probably should use this ?

Charlie
"Ben Hinkle" <ben.hinkle gmail.com> wrote in message
news:d4rt0d$229n$1 digitaldaemon.com...
 Interesting. I don't know much about sockets but the socketstream.readline
 doesn't read the last \n when it sees the \r - it leaves it in the stream
 until the next read. I assume that's because readLine doesn't actually
know
 if there is a \n coming and it doesn't want to block waiting for one. It
 seems, though, that leaving that char in the stream gets in the way of
 future send/recv calls. It doesn't matter what that last char is or if it
 just reads an incomplete amount of data. Is there a way to know if the
line
 ending is \r or \r\n ahead of time or is there some setting on the socket
 that will fix it? Again I don't know the details of how sockets send and
 recieve so someone else besides me will have to help out (I generally take
 generic stream questions but this one seems out of my realm).

 "Michael Butscher" <mbutscher gmx.de> wrote in message
 news:MPG.1cdb6332bdc3cce0989681 news.digitalmars.com...
 Hi,

 could please somebody explain me why the following code doesn't work
 properly?

 It was tested on Windows ME, so you have to link with ws2_32.lib to
 compile it.

 The code starts 2 threads, a server and a client which communicate by a
 TCP
 socket. The client sends a single line (ending with "\r\n") as a request
 to the
 server, the server reads it and responds with exactly 100000 bytes of
 data, but
 the client receives only a part of the data.

 Curiously, the code works perfectly well if the request string only ends
 with
 "\n".

 After I replaced SocketStream.readLine() with a slightly modified
function
 which
 ignores "\r" characters, it worked also.

 Thanks in advance


 Michael
Apr 28 2005
parent "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Charlie" <charles jwavro.com> wrote in message 
news:d4rtoi$2309$1 digitaldaemon.com...
 Hmm, win32 and linux both use \n as the 'last' char to denote a new line,
 probably should use this ?
The trouble is that mac line endings might be coming down the stream and you don't know before-hand. Just because the code reading the stream is on win32 or linux doesn't mean the code that wrote to the stream is using that platform's line endings. The general Stream class does a getc when it sees a \r to scarf up any following \n and it has always bothered me that the getc might block as it waits for the next char. Maybe the right thing to do is put some "peeking" code into streamsocket that scarfs up the \n if it is available. Does anyone know if the \n will always be peekable if one is there?
Apr 28 2005
prev sibling parent reply Vathix <vathix dprogramming.com> writes:
On Thu, 28 Apr 2005 16:17:15 -0400, Michael Butscher <mbutscher gmx.de>  
wrote:

 Hi,

 could please somebody explain me why the following code doesn't work  
 properly?
While I was running your code I noticed the client will start working correctly if the console has focus for awhile and/or if you hit enter or move the mouse over it. I even rewrote it to not use the SocketStream and still ran into read problems on the client side. I'll mess around with it some more. - Chris
Apr 29 2005
parent Michael Butscher <mbutscher gmx.de> writes:
Vathix wrote:

 While I was running your code I noticed the client will start working  
 correctly if the console has focus for awhile and/or if you hit enter or  
 move the mouse over it. I even rewrote it to not use the SocketStream and  
 still ran into read problems on the client side. I'll mess around with it  
 some more.
It seems that it works (at least better), if the server pauses a bit between sending data and closing the socket (e. g. by a dummy for-loop) Michael
Apr 29 2005