Thread overview
Problem with SocketStream.readLine
Apr 28, 2005
Michael Butscher
Apr 28, 2005
Ben Hinkle
Apr 29, 2005
Charlie
Apr 29, 2005
Ben Hinkle
Apr 29, 2005
Vathix
Apr 29, 2005
Michael Butscher
April 28, 2005
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;
}


--------------------------------------------------


April 28, 2005
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


April 29, 2005
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
>
>


April 29, 2005
"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?


April 29, 2005
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
April 29, 2005
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